summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--.gitlab/CODEOWNERS14
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml6
-rw-r--r--.gitlab/issue_templates/Security Release.md20
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md2
-rw-r--r--CHANGELOG.md13
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/javascripts/boards/services/board_service.js5
-rw-r--r--app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue2
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue5
-rw-r--r--app/assets/javascripts/jobs/index.js29
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue51
-rw-r--r--app/assets/javascripts/monitoring/components/panel_type.vue41
-rw-r--r--app/assets/javascripts/notes/stores/utils.js2
-rw-r--r--app/assets/javascripts/operation_settings/components/external_dashboard.vue2
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue2
-rw-r--r--app/assets/javascripts/right_sidebar.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue11
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss16
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/finders/branches_finder.rb2
-rw-r--r--app/finders/container_repositories_finder.rb34
-rw-r--r--app/models/clusters/applications/cert_manager.rb36
-rw-r--r--app/models/concerns/relative_positioning.rb111
-rw-r--r--app/models/group.rb2
-rw-r--r--app/policies/group_policy.rb1
-rw-r--r--app/serializers/analytics_issue_entity.rb2
-rw-r--r--app/views/admin/users/_access_levels.html.haml4
-rw-r--r--app/views/projects/_flash_messages.html.haml2
-rw-r--r--app/views/projects/jobs/show.html.haml3
-rw-r--r--app/views/projects/services/prometheus/_metrics.html.haml56
-rw-r--r--app/views/projects/services/prometheus/_show.html.haml9
-rw-r--r--app/workers/chaos/kill_worker.rb2
-rw-r--r--changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml6
-rw-r--r--changelogs/unreleased/60664-kubernetes-applications-uninstall-cert-manager.yml5
-rw-r--r--changelogs/unreleased/64675-Dashboard-URL-legend-border.yml5
-rw-r--r--changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml5
-rw-r--r--changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml5
-rw-r--r--changelogs/unreleased/fix-i18n-updated-projects.yml5
-rw-r--r--changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml5
-rw-r--r--changelogs/unreleased/jprovazn-fix-positioning.yml5
-rw-r--r--changelogs/unreleased/leipert-improve-ansi2html.yml5
-rw-r--r--changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml5
-rw-r--r--changelogs/unreleased/patch-72.yml5
-rw-r--r--changelogs/unreleased/sh-disable-redis-peek.yml5
-rw-r--r--changelogs/unreleased/sh-use-redis-caching-store.yml5
-rw-r--r--changelogs/unreleased/update-pipelines-minutes-expiry-banner-to-an-alert-component-type.yml5
-rw-r--r--config/application.rb5
-rw-r--r--db/migrate/20190802012622_reorder_issues_project_id_relative_position_index.rb24
-rw-r--r--db/schema.rb4
-rw-r--r--doc/administration/gitaly/index.md18
-rw-r--r--doc/administration/index.md3
-rw-r--r--doc/administration/plugins.md32
-rw-r--r--doc/administration/repository_storage_paths.md16
-rw-r--r--doc/administration/troubleshooting/diagnostics_tools.md27
-rw-r--r--doc/administration/troubleshooting/elasticsearch.md345
-rw-r--r--doc/api/container_registry.md77
-rw-r--r--doc/customization/branded_login_page.md35
-rw-r--r--doc/customization/branded_page_and_email_header.md34
-rw-r--r--doc/customization/favicon.md31
-rw-r--r--doc/customization/help_message.md37
-rw-r--r--doc/customization/index.md20
-rw-r--r--doc/customization/libravatar.md65
-rw-r--r--doc/customization/new_project_page.md36
-rw-r--r--doc/development/README.md4
-rw-r--r--doc/development/contributing/issue_workflow.md6
-rw-r--r--doc/install/requirements.md4
-rw-r--r--doc/integration/elasticsearch.md21
-rw-r--r--doc/raketasks/backup_restore.md19
-rw-r--r--doc/topics/git/index.md1
-rw-r--r--doc/topics/git/partial_clone.md147
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md5
-rw-r--r--doc/user/clusters/applications.md35
-rw-r--r--doc/user/permissions.md6
-rw-r--r--doc/user/project/integrations/prometheus.md5
-rw-r--r--doc/user/project/pipelines/settings.md7
-rw-r--r--doc/user/project/quick_actions.md13
-rw-r--r--lib/api/api.rb3
-rw-r--r--lib/api/entities/container_registry.rb10
-rw-r--r--lib/api/group_container_repositories.rb39
-rw-r--r--lib/api/project_container_repositories.rb (renamed from lib/api/container_registry.rb)21
-rw-r--r--lib/gitlab/background_migration/migrate_legacy_artifacts.rb18
-rw-r--r--lib/gitlab/cycle_analytics/base_query.rb13
-rw-r--r--lib/gitlab/cycle_analytics/code_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/issue_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/issue_helper.rb13
-rw-r--r--lib/gitlab/cycle_analytics/plan_event_fetcher.rb4
-rw-r--r--lib/gitlab/cycle_analytics/plan_helper.rb6
-rw-r--r--lib/gitlab/cycle_analytics/production_event_fetcher.rb1
-rw-r--r--lib/gitlab/cycle_analytics/review_event_fetcher.rb4
-rw-r--r--lib/peek/views/redis_detailed.rb5
-rw-r--r--locale/gitlab.pot10
-rw-r--r--package.json2
-rw-r--r--spec/factories/clusters/applications/helm.rb14
-rw-r--r--spec/features/projects/clusters/applications_spec.rb2
-rw-r--r--spec/finders/container_repositories_finder_spec.rb44
-rw-r--r--spec/fixtures/api/schemas/registry/repository.json6
-rw-r--r--spec/fixtures/clusters/sample_key.key9
-rw-r--r--spec/javascripts/jobs/components/job_app_spec.js1
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb40
-rw-r--r--spec/models/group_spec.rb1
-rw-r--r--spec/requests/api/group_container_repositories_spec.rb57
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb (renamed from spec/requests/api/container_registry_spec.rb)75
-rw-r--r--spec/serializers/analytics_issue_entity_spec.rb6
-rw-r--r--spec/serializers/analytics_issue_serializer_spec.rb6
-rw-r--r--spec/serializers/analytics_merge_request_serializer_spec.rb6
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb2
-rw-r--r--spec/support/shared_examples/container_repositories_shared_examples.rb58
-rw-r--r--spec/support/shared_examples/relative_positioning_shared_examples.rb102
-rw-r--r--yarn.lock8
112 files changed, 1822 insertions, 447 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5b39304444c..9086da10283 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,7 +29,6 @@ stages:
- qa
- post-test
- pages
- - post-cleanup
include:
- local: .gitlab/ci/global.gitlab-ci.yml
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 13c8b4a8458..cb3bc544132 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1,6 +1,6 @@
# Backend Maintainers are the default for all ruby files
-*.rb @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @mayra-cabrera @nick.thomas @rspeicher @rymai @reprazent @smcgivern @tkuah
-*.rake @ashmckenzie @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @mkozono @mayra-cabrera @nick.thomas @rspeicher @rymai @reprazent @smcgivern @tkuah
+*.rb @gitlab-org/maintainers/rails-backend
+*.rake @gitlab-org/maintainers/rails-backend
# Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia @eread @mikelewis
@@ -10,11 +10,11 @@ app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallma
*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter
# Maintainers from the Database team should review changes in `db/`
-db/ @abrandl @NikolayS
-lib/gitlab/background_migration/ @abrandl @NikolayS
-lib/gitlab/database/ @abrandl @NikolayS
-lib/gitlab/sql/ @abrandl @NikolayS
-/ee/db/ @abrandl @NikolayS
+db/ @gl-database
+lib/gitlab/background_migration/ @gl-database
+lib/gitlab/database/ @gl-database
+lib/gitlab/sql/ @gl-database
+/ee/db/ @gl-database
# Feature specific owners
/ee/lib/gitlab/code_owners/ @reprazent
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 5a3940bdac2..39ae62a43c9 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -15,7 +15,7 @@ review-docs-deploy-manual:
extends:
- .review-docs
- .no-docs-and-no-qa
- stage: build
+ stage: review
script:
- gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
@@ -28,7 +28,7 @@ review-docs-deploy-manual:
# Useful to preview the docs changes live.
review-docs-deploy:
<<: *review-docs
- stage: post-test
+ stage: review
script:
- gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
@@ -41,7 +41,7 @@ review-docs-deploy:
# Cleanup remote environment of gitlab-docs
review-docs-cleanup:
<<: *review-docs
- stage: post-cleanup
+ stage: review
environment:
name: review-docs/$CI_COMMIT_REF_SLUG
action: stop
diff --git a/.gitlab/issue_templates/Security Release.md b/.gitlab/issue_templates/Security Release.md
index ae469d3b125..3e60274623e 100644
--- a/.gitlab/issue_templates/Security Release.md
+++ b/.gitlab/issue_templates/Security Release.md
@@ -1,7 +1,7 @@
<!--
# Read me first!
-Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
+Set the title to: `Security Release: 12.2.X, 12.1.X, and 12.0.X`
-->
## Releases tasks
@@ -12,9 +12,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
## Version issues:
-* 11.4.X: {release task link}
-* 11.3.X: {release task link}
-* 11.2.X: {release task link}
+* 12.2.X: {release task link}
+* 12.1.X: {release task link}
+* 12.0.X: {release task link}
## Security Issues:
@@ -34,9 +34,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR |
|---------|----|
-| 11.4 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
-| 11.3 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
-| 11.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.2 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.1 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
+| 12.0 | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlabhq/merge_requests/ link} |
@@ -48,9 +48,9 @@ Set the title to: `Security Release: 11.4.X, 11.3.X, and 11.2.X`
| Version | MR |
|---------|----|
-| 11.4| {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
-| 11.3 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
-| 11.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.2 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.1 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
+| 12.0 | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
| master | {https://dev.gitlab.org/gitlab/gitlab-ee/merge_requests/ link} |
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index 7857afb66c2..3e634de4f0c 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -17,7 +17,7 @@ Set the title to: `Description of the original issue`
#### Backports
-- [ ] Once the MR is ready to be merged, create MRs targeting the last 3 releases, plus the current RC if between the 7th and 22nd of the month.
+- [ ] Once the MR is ready to be merged, create MRs targeting the latest 3 stable branches
- [ ] At this point, it might be easy to squash the commits from the MR into one
- You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the "Security Release" merge request template.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 15b55f01c32..0752708d5e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.1.4
+
+### Fixed (3 changes, 1 of them is from the community)
+
+- Properly translate term in projects list. !30958
+- Add exclusive lease to mergeability check process. !31082
+- Fix Docker in Docker (DIND) listen port behavior change by adding DOCKER_TLS_CERTDIR in CI job templates. !31201 (Cameron Boulton)
+
+### Performance (1 change)
+
+- Improve job log rendering performance. !31262
+
+
## 12.1.3
### Fixed (11 changes)
diff --git a/Gemfile b/Gemfile
index 61a6432a953..ef277336859 100644
--- a/Gemfile
+++ b/Gemfile
@@ -170,7 +170,7 @@ gem 'acts-as-taggable-on', '~> 6.0'
gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.6.0'
-gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch'
+gem 'gitlab-sidekiq-fetcher', '0.5.1', require: 'sidekiq-reliable-fetch'
# Cron Parser
gem 'fugit', '~> 1.2.1'
@@ -200,13 +200,13 @@ gem 'js_regex', '~> 3.1'
# User agent parsing
gem 'device_detector'
-# Cache
-gem 'redis-rails', '~> 5.0.2'
-
# Redis
-gem 'redis', '~> 3.2'
+gem 'redis', '~> 4.0'
gem 'connection_pool', '~> 2.0'
+# Redis session store
+gem 'redis-rails', '~> 5.0.2'
+
# Discord integration
gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index f89654c82fd..368cbef4577 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -319,7 +319,7 @@ GEM
jaeger-client (~> 0.10)
opentracing (~> 0.4)
gitlab-markup (1.7.0)
- gitlab-sidekiq-fetcher (0.4.0)
+ gitlab-sidekiq-fetcher (0.5.1)
sidekiq (~> 5)
gitlab-styles (2.8.0)
rubocop (~> 0.69.0)
@@ -741,17 +741,17 @@ GEM
recaptcha (4.13.1)
json
recursive-open-struct (1.1.0)
- redis (3.3.5)
+ redis (4.1.2)
redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 2)
- redis-activesupport (5.0.4)
+ redis-activesupport (5.0.7)
activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2)
redis-namespace (1.6.0)
redis (>= 3.0.4)
- redis-rack (2.0.4)
+ redis-rack (2.0.5)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
redis-rails (5.0.2)
@@ -1102,7 +1102,7 @@ DEPENDENCIES
github-markup (~> 1.7.0)
gitlab-labkit (~> 0.3.0)
gitlab-markup (~> 1.7.0)
- gitlab-sidekiq-fetcher (~> 0.4.0)
+ gitlab-sidekiq-fetcher (= 0.5.1)
gitlab-styles (~> 2.7)
gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2)
@@ -1197,7 +1197,7 @@ DEPENDENCIES
rdoc (~> 6.0)
re2 (~> 1.1.1)
recaptcha (~> 4.11)
- redis (~> 3.2)
+ redis (~> 4.0)
redis-namespace (~> 1.6.0)
redis-rails (~> 5.0.2)
request_store (~> 1.3)
diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js
index 5202620057c..56a6cab6c73 100644
--- a/app/assets/javascripts/boards/services/board_service.js
+++ b/app/assets/javascripts/boards/services/board_service.js
@@ -1,4 +1,9 @@
/* eslint-disable class-methods-use-this */
+/**
+ * This file is intended to be deleted.
+ * The existing functions will removed one by one in favor of using the board store directly.
+ * see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621
+ */
import boardsStore from '~/boards/stores/boards_store';
diff --git a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
index e067eb13c54..4f60e543666 100644
--- a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
+++ b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
@@ -12,7 +12,7 @@ const CUSTOM_APP_WARNING_TEXT = {
'ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored.',
),
[CERT_MANAGER]: s__(
- 'ClusterIntegration|The associated certifcate will be deleted and cannot be restored.',
+ 'ClusterIntegration|The associated private key will be deleted and cannot be restored.',
),
[PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'),
[RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'),
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index ef9fb6d08d1..8da87f424c4 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -73,6 +73,10 @@ export default {
type: String,
required: true,
},
+ projectPath: {
+ type: String,
+ required: true,
+ },
logState: {
type: String,
required: true,
@@ -258,6 +262,7 @@ export default {
:quota-used="job.runners.quota.used"
:quota-limit="job.runners.quota.limit"
:runners-path="runnerHelpUrl"
+ :project-path="projectPath"
/>
<environments-block
diff --git a/app/assets/javascripts/jobs/index.js b/app/assets/javascripts/jobs/index.js
index 06514fcce1d..add7f9b710a 100644
--- a/app/assets/javascripts/jobs/index.js
+++ b/app/assets/javascripts/jobs/index.js
@@ -10,16 +10,29 @@ export default () => {
JobApp,
},
render(createElement) {
+ const {
+ deploymentHelpUrl,
+ runnerHelpUrl,
+ runnerSettingsUrl,
+ variablesSettingsUrl,
+ endpoint,
+ pagePath,
+ logState,
+ buildStatus,
+ projectPath,
+ } = element.dataset;
+
return createElement('job-app', {
props: {
- deploymentHelpUrl: element.dataset.deploymentHelpUrl,
- runnerHelpUrl: element.dataset.runnerHelpUrl,
- runnerSettingsUrl: element.dataset.runnerSettingsUrl,
- variablesSettingsUrl: element.dataset.variablesSettingsUrl,
- endpoint: element.dataset.endpoint,
- pagePath: element.dataset.buildOptionsPagePath,
- logState: element.dataset.buildOptionsLogState,
- buildStatus: element.dataset.buildOptionsBuildStatus,
+ deploymentHelpUrl,
+ runnerHelpUrl,
+ runnerSettingsUrl,
+ variablesSettingsUrl,
+ endpoint,
+ pagePath,
+ logState,
+ buildStatus,
+ projectPath,
},
});
},
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 45543ef2cc8..2feb545199b 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -1,5 +1,12 @@
<script>
-import { GlButton, GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlModal,
+ GlModalDirective,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
@@ -30,7 +37,8 @@ export default {
GlModal,
},
directives: {
- GlModalDirective,
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
},
props: {
externalDashboardUrl: {
@@ -328,7 +336,7 @@ export default {
<div class="d-flex">
<div v-if="addingMetricsAvailable">
<gl-button
- v-gl-modal-directive="$options.addMetric.modalId"
+ v-gl-modal="$options.addMetric.modalId"
class="js-add-metric-button text-success border-success"
>{{ $options.addMetric.title }}</gl-button
>
@@ -395,14 +403,35 @@ export default {
:project-path="projectPath"
group-id="monitor-area-chart"
>
- <alert-widget
- v-if="alertWidgetAvailable && graphData"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.queries"
- :alerts-to-manage="getGraphAlerts(graphData.queries)"
- :modal-id="`alert-modal-${index}-${graphIndex}`"
- @setAlerts="setAlerts"
- />
+ <div class="d-flex align-items-center">
+ <alert-widget
+ v-if="alertWidgetAvailable && graphData"
+ :modal-id="`alert-modal-${index}-${graphIndex}`"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.queries"
+ :alerts-to-manage="getGraphAlerts(graphData.queries)"
+ @setAlerts="setAlerts"
+ />
+ <gl-dropdown
+ v-if="alertWidgetAvailable"
+ v-gl-tooltip
+ class="mx-2"
+ toggle-class="btn btn-transparent border-0"
+ :right="true"
+ :no-caret="true"
+ :title="__('More actions')"
+ >
+ <template slot="button-content">
+ <icon name="ellipsis_v" class="text-secondary" />
+ </template>
+ <gl-dropdown-item
+ v-if="alertWidgetAvailable"
+ v-gl-modal="`alert-modal-${index}-${graphIndex}`"
+ >
+ {{ __('Alerts') }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
</monitor-area-chart>
</template>
</graph-group>
diff --git a/app/assets/javascripts/monitoring/components/panel_type.vue b/app/assets/javascripts/monitoring/components/panel_type.vue
index f1f02964a29..295c0851f12 100644
--- a/app/assets/javascripts/monitoring/components/panel_type.vue
+++ b/app/assets/javascripts/monitoring/components/panel_type.vue
@@ -1,6 +1,7 @@
<script>
import { mapState } from 'vuex';
import _ from 'underscore';
+import { GlDropdown, GlDropdownItem, GlModal, GlModalDirective } from '@gitlab/ui';
import MonitorAreaChart from './charts/area.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
import MonitorEmptyChart from './charts/empty_chart.vue';
@@ -10,6 +11,12 @@ export default {
MonitorAreaChart,
MonitorSingleStatChart,
MonitorEmptyChart,
+ GlDropdown,
+ GlDropdownItem,
+ GlModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
},
props: {
graphData: {
@@ -64,14 +71,32 @@ export default {
:container-width="dashboardWidth"
group-id="monitor-area-chart"
>
- <alert-widget
- v-if="alertWidgetAvailable"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.queries"
- :alerts-to-manage="getGraphAlerts(graphData.queries)"
- :modal-id="`alert-modal-${index}`"
- @setAlerts="setAlerts"
- />
+ <div class="d-flex align-items-center">
+ <alert-widget
+ v-if="alertWidgetAvailable && graphData"
+ :modal-id="`alert-modal-${index}`"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.queries"
+ :alerts-to-manage="getGraphAlerts(graphData.queries)"
+ @setAlerts="setAlerts"
+ />
+ <gl-dropdown
+ v-if="alertWidgetAvailable"
+ v-gl-tooltip
+ class="mx-2"
+ toggle-class="btn btn-transparent border-0"
+ :right="true"
+ :no-caret="true"
+ :title="__('More actions')"
+ >
+ <template slot="button-content">
+ <icon name="ellipsis_v" class="text-secondary" />
+ </template>
+ <gl-dropdown-item v-if="alertWidgetAvailable" v-gl-modal="`alert-modal-${index}`">
+ {{ __('Alerts') }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
</monitor-area-chart>
<monitor-empty-chart v-else :graph-title="graphData.title" />
</template>
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index ed4cef4a917..97dcd54fe88 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -21,7 +21,7 @@ export const getQuickActionText = note => {
text = __('Applying multiple commands');
} else {
const commandDescription = executedCommands[0].description.toLowerCase();
- text = sprintf(__('Applying command to %{commandDescription}', { commandDescription }));
+ text = sprintf(__('Applying command to %{commandDescription}'), { commandDescription });
}
}
diff --git a/app/assets/javascripts/operation_settings/components/external_dashboard.vue b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
index ed518611d0b..3c5de189d51 100644
--- a/app/assets/javascripts/operation_settings/components/external_dashboard.vue
+++ b/app/assets/javascripts/operation_settings/components/external_dashboard.vue
@@ -50,9 +50,11 @@ export default {
<form>
<gl-form-group
:label="s__('ExternalMetrics|Full dashboard URL')"
+ label-for="full-dashboard-url"
:description="s__('ExternalMetrics|Enter the URL of the dashboard you want to link to')"
>
<gl-form-input
+ id="full-dashboard-url"
v-model="userDashboardUrl"
placeholder="https://my-org.gitlab.io/my-dashboards"
@keydown.enter.native.prevent="updateExternalDashboardUrl"
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index 9bc3e6388e3..24612c8681a 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -166,7 +166,7 @@ export default {
<section class="media-section">
<div class="media">
<status-icon :status="statusIconName" :size="24" />
- <div class="media-body d-flex flex-align-self-center prepend-left-default">
+ <div class="media-body d-flex flex-align-self-center">
<span class="js-code-text code-text">
{{ headerText }}
<slot :name="slotName"></slot>
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 930c0d5e958..40a2158de78 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -101,10 +101,12 @@ Sidebar.prototype.toggleTodo = function(e) {
this.todoUpdateDone(data);
})
.catch(() =>
- flash(sprintf(__('There was an error %{message} todo.')), {
- message:
- ajaxType === 'post' ? s__('RightSidebar|adding a') : s__('RightSidebar|deleting the'),
- }),
+ flash(
+ sprintf(__('There was an error %{message} todo.'), {
+ message:
+ ajaxType === 'post' ? s__('RightSidebar|adding a') : s__('RightSidebar|deleting the'),
+ }),
+ ),
);
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index 17ac8ada32d..76b96c8c1c0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -60,7 +60,7 @@ export default {
return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
},
showVisualReviewAppLink() {
- return Boolean(this.mr.visualReviewFF && this.mr.visualReviewAppAvailable);
+ return this.mr.visualReviewAppAvailable;
},
showMergeTrainInfo() {
return _.isNumber(this.mr.mergeTrainIndex);
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index 8dbd9e52cfe..13e4b061fda 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -32,10 +32,13 @@ export default {
};
</script>
<template>
- <div class="d-flex widget-status-icon">
- <div v-if="isLoading" class="mr-widget-icon"><gl-loading-icon size="sm" /></div>
-
- <ci-icon v-else :status="statusObj" :size="24" />
+ <div class="d-flex align-self-start">
+ <div class="square s24 h-auto d-flex-center append-right-default">
+ <div v-if="isLoading" class="mr-widget-icon">
+ <gl-loading-icon size="sm" />
+ </div>
+ <ci-icon v-else :status="statusObj" :size="24" />
+ </div>
<button
v-if="showDisabledButton"
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 2780afa11fa..cb7913ee54e 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -88,7 +88,7 @@
}
.mr-widget-info {
- padding-left: $gl-padding-50 - $gl-padding-32;
+ padding-left: $gl-padding;
padding-right: $gl-padding;
}
@@ -262,23 +262,11 @@
}
}
- .widget-status-icon {
- align-self: flex-start;
-
- button {
- margin-left: $gl-padding;
- }
- }
-
.mr-widget-body {
line-height: 28px;
@include clearfix;
- button {
- margin-left: $gl-padding;
- }
-
.approve-btn {
margin-right: 5px;
}
@@ -527,7 +515,7 @@
}
.mr-links {
- padding-left: $status-icon-size + $gl-btn-padding;
+ padding-left: $gl-padding-8 + $status-icon-size + $gl-btn-padding;
&:last-child {
padding-bottom: $gl-padding;
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 141a7dfb923..e7bdb4b2042 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -49,7 +49,7 @@ class Projects::BranchesController < Projects::ApplicationController
branches = BranchesFinder.new(repository, params.permit(names: [])).execute
Gitlab::GitalyClient.allow_n_plus_1_calls do
- render json: branches.to_h { |branch| [branch.name, service.call(branch)] }
+ render json: branches.map { |branch| [branch.name, service.call(branch)] }.to_h
end
end
end
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index b462c8053fa..291a24c1405 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -69,7 +69,7 @@ class BranchesFinder
return branches unless names
branch_names = names.to_set
- branches.filter do |branch|
+ branches.select do |branch|
branch_names.include?(branch.name)
end
end
diff --git a/app/finders/container_repositories_finder.rb b/app/finders/container_repositories_finder.rb
new file mode 100644
index 00000000000..eb91d7f825b
--- /dev/null
+++ b/app/finders/container_repositories_finder.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class ContainerRepositoriesFinder
+ # id: group or project id
+ # container_type: :group or :project
+ def initialize(id:, container_type:)
+ @id = id
+ @type = container_type.to_sym
+ end
+
+ def execute
+ if project_type?
+ project.container_repositories
+ else
+ group.container_repositories
+ end
+ end
+
+ private
+
+ attr_reader :id, :type
+
+ def project_type?
+ type == :project
+ end
+
+ def project
+ Project.find(id)
+ end
+
+ def group
+ Group.find(id)
+ end
+end
diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb
index 7d5a6dec519..2fc1b67dfd2 100644
--- a/app/models/clusters/applications/cert_manager.rb
+++ b/app/models/clusters/applications/cert_manager.rb
@@ -24,12 +24,6 @@ module Clusters
'stable/cert-manager'
end
- # We will implement this in future MRs.
- # Need to reverse postinstall step
- def allowed_to_uninstall?
- false
- end
-
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: 'certmanager',
@@ -41,12 +35,42 @@ module Clusters
)
end
+ def uninstall_command
+ Gitlab::Kubernetes::Helm::DeleteCommand.new(
+ name: 'certmanager',
+ rbac: cluster.platform_kubernetes_rbac?,
+ files: files,
+ postdelete: post_delete_script
+ )
+ end
+
private
def post_install_script
["kubectl create -f /data/helm/certmanager/config/cluster_issuer.yaml"]
end
+ def post_delete_script
+ [
+ delete_private_key,
+ delete_crd('certificates.certmanager.k8s.io'),
+ delete_crd('clusterissuers.certmanager.k8s.io'),
+ delete_crd('issuers.certmanager.k8s.io')
+ ].compact
+ end
+
+ def private_key_name
+ @private_key_name ||= cluster_issuer_content.dig('spec', 'acme', 'privateKeySecretRef', 'name')
+ end
+
+ def delete_private_key
+ "kubectl delete secret -n #{Gitlab::Kubernetes::Helm::NAMESPACE} #{private_key_name} --ignore-not-found" if private_key_name.present?
+ end
+
+ def delete_crd(definition)
+ "kubectl delete crd #{definition} --ignore-not-found"
+ end
+
def cluster_issuer_file
{
'cluster_issuer.yaml': cluster_issuer_yaml_content
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 4a1441805fc..6d3c7a7ed68 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -29,10 +29,6 @@ module RelativePositioning
MAX_POSITION = Gitlab::Database::MAX_INT_VALUE
IDEAL_DISTANCE = 500
- included do
- after_save :save_positionable_neighbours
- end
-
class_methods do
def move_nulls_to_end(objects)
objects = objects.reject(&:relative_position)
@@ -114,11 +110,12 @@ module RelativePositioning
return move_after(before) unless after
return move_before(after) unless before
- # If there is no place to insert an item we need to create one by moving the before item closer
- # to its predecessor. This process will recursively move all the predecessors until we have a place
+ # If there is no place to insert an item we need to create one by moving the item
+ # before this and all preceding items until there is a gap
+ before, after = after, before if after.relative_position < before.relative_position
if (after.relative_position - before.relative_position) < 2
- before.move_before
- @positionable_neighbours = [before] # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ after.move_sequence_before
+ before.reset
end
self.relative_position = self.class.position_between(before.relative_position, after.relative_position)
@@ -128,12 +125,8 @@ module RelativePositioning
pos_before = before.relative_position
pos_after = before.next_relative_position
- if before.shift_after?
- item_to_move = self.class.relative_positioning_query_base(self).find_by!(relative_position: pos_after)
- item_to_move.move_after
- @positionable_neighbours = [item_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
-
- pos_after = item_to_move.relative_position
+ if pos_after && (pos_after - pos_before) < 2
+ before.move_sequence_after
end
self.relative_position = self.class.position_between(pos_before, pos_after)
@@ -143,12 +136,8 @@ module RelativePositioning
pos_after = after.relative_position
pos_before = after.prev_relative_position
- if after.shift_before?
- item_to_move = self.class.relative_positioning_query_base(self).find_by!(relative_position: pos_before)
- item_to_move.move_before
- @positionable_neighbours = [item_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables
-
- pos_before = item_to_move.relative_position
+ if pos_before && (pos_after - pos_before) < 2
+ after.move_sequence_before
end
self.relative_position = self.class.position_between(pos_before, pos_after)
@@ -162,36 +151,82 @@ module RelativePositioning
self.relative_position = self.class.position_between(min_relative_position || START_POSITION, MIN_POSITION)
end
- # Indicates if there is an item that should be shifted to free the place
- def shift_after?
- next_pos = next_relative_position
- next_pos && (next_pos - relative_position) == 1
+ # Moves the sequence before the current item to the middle of the next gap
+ # For example, we have 5 11 12 13 14 15 and the current item is 15
+ # This moves the sequence 11 12 13 14 to 8 9 10 11
+ def move_sequence_before
+ next_gap = find_next_gap_before
+ delta = optimum_delta_for_gap(next_gap)
+
+ move_sequence(next_gap[:start], relative_position, -delta)
end
- # Indicates if there is an item that should be shifted to free the place
- def shift_before?
- prev_pos = prev_relative_position
- prev_pos && (relative_position - prev_pos) == 1
+ # Moves the sequence after the current item to the middle of the next gap
+ # For example, we have 11 12 13 14 15 21 and the current item is 11
+ # This moves the sequence 12 13 14 15 to 15 16 17 18
+ def move_sequence_after
+ next_gap = find_next_gap_after
+ delta = optimum_delta_for_gap(next_gap)
+
+ move_sequence(relative_position, next_gap[:start], delta)
end
private
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- def save_positionable_neighbours
- return unless @positionable_neighbours
+ # Supposing that we have a sequence of items: 1 5 11 12 13 and the current item is 13
+ # This would return: `{ start: 11, end: 5 }`
+ def find_next_gap_before
+ items_with_next_pos = scoped_items
+ .select('relative_position AS pos, LEAD(relative_position) OVER (ORDER BY relative_position DESC) AS next_pos')
+ .where('relative_position <= ?', relative_position)
+ .order(relative_position: :desc)
+
+ find_next_gap(items_with_next_pos).tap do |gap|
+ gap[:end] ||= MIN_POSITION
+ end
+ end
+
+ # Supposing that we have a sequence of items: 13 14 15 20 24 and the current item is 13
+ # This would return: `{ start: 15, end: 20 }`
+ def find_next_gap_after
+ items_with_next_pos = scoped_items
+ .select('relative_position AS pos, LEAD(relative_position) OVER (ORDER BY relative_position ASC) AS next_pos')
+ .where('relative_position >= ?', relative_position)
+ .order(:relative_position)
- status = @positionable_neighbours.all? { |item| item.save(touch: false) }
- @positionable_neighbours = nil
+ find_next_gap(items_with_next_pos).tap do |gap|
+ gap[:end] ||= MAX_POSITION
+ end
+ end
+
+ def find_next_gap(items_with_next_pos)
+ gap = self.class.from(items_with_next_pos, :items_with_next_pos)
+ .where('ABS(pos - next_pos) > 1 OR next_pos IS NULL')
+ .limit(1)
+ .pluck(:pos, :next_pos)
+ .first
+
+ { start: gap[0], end: gap[1] }
+ end
- status
+ def optimum_delta_for_gap(gap)
+ delta = ((gap[:start] - gap[:end]) / 2.0).abs.ceil
+
+ [delta, IDEAL_DISTANCE].min
+ end
+
+ def move_sequence(start_pos, end_pos, delta)
+ scoped_items
+ .where.not(id: self.id)
+ .where('relative_position BETWEEN ? AND ?', start_pos, end_pos)
+ .update_all("relative_position = relative_position + #{delta}")
end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
def calculate_relative_position(calculation)
# When calculating across projects, this is much more efficient than
# MAX(relative_position) without the GROUP BY, due to index usage:
# https://gitlab.com/gitlab-org/gitlab-ce/issues/54276#note_119340977
- relation = self.class.relative_positioning_query_base(self)
+ relation = scoped_items
.order(Gitlab::Database.nulls_last_order('position', 'DESC'))
.group(self.class.relative_positioning_parent_column)
.limit(1)
@@ -203,4 +238,8 @@ module RelativePositioning
.first&.
last
end
+
+ def scoped_items
+ self.class.relative_positioning_query_base(self)
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 74eb556b1b5..6c868b1d1f0 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -44,6 +44,8 @@ class Group < Namespace
has_many :cluster_groups, class_name: 'Clusters::Group'
has_many :clusters, through: :cluster_groups, class_name: 'Clusters::Cluster'
+ has_many :container_repositories, through: :projects
+
has_many :todos
accepts_nested_attributes_for :variables, allow_destroy: true
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 84b1873c05d..52c944491bf 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -68,6 +68,7 @@ class GroupPolicy < BasePolicy
rule { developer }.enable :admin_milestone
rule { reporter }.policy do
+ enable :read_container_image
enable :admin_label
enable :admin_list
enable :admin_issue
diff --git a/app/serializers/analytics_issue_entity.rb b/app/serializers/analytics_issue_entity.rb
index 29d4a6ae1d0..307ce14a921 100644
--- a/app/serializers/analytics_issue_entity.rb
+++ b/app/serializers/analytics_issue_entity.rb
@@ -26,6 +26,6 @@ class AnalyticsIssueEntity < Grape::Entity
private
def url_to(route, object)
- public_send("#{route}_url", object[:path], object[:name], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("#{route}_url", object[:namespace_path], object[:project_path], object[:iid].to_s) # rubocop:disable GitlabSecurity/PublicSend
end
end
diff --git a/app/views/admin/users/_access_levels.html.haml b/app/views/admin/users/_access_levels.html.haml
index 77729636f9d..bb1e22cc610 100644
--- a/app/views/admin/users/_access_levels.html.haml
+++ b/app/views/admin/users/_access_levels.html.haml
@@ -19,7 +19,7 @@
- editing_current_user = (current_user == @user)
= f.radio_button :access_level, :regular, disabled: editing_current_user
- = label_tag :regular, class: 'font-weight-bold' do
+ = f.label :access_level_regular, class: 'font-weight-bold' do
Regular
%p.light
Regular users have access to their groups and projects
@@ -27,7 +27,7 @@
= render_if_exists 'admin/users/auditor_access_level_radio', f: f, disabled: editing_current_user
= f.radio_button :access_level, :admin, disabled: editing_current_user
- = label_tag :admin, class: 'font-weight-bold' do
+ = f.label :access_level_admin, class: 'font-weight-bold' do
Admin
%p.light
Administrators have access to all groups, projects and users and can manage all features in this installation
diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml
index d95045c9cce..f9222387e97 100644
--- a/app/views/projects/_flash_messages.html.haml
+++ b/app/views/projects/_flash_messages.html.haml
@@ -5,7 +5,7 @@
- if current_user && can?(current_user, :download_code, project)
= render 'shared/no_ssh'
= render 'shared/no_password'
- = render_if_exists 'shared/shared_runners_minutes_limit', project: project
- unless project.empty_repo?
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
= render_if_exists 'projects/above_size_limit_warning', project: project
+ = render_if_exists 'shared/shared_runners_minutes_limit', project: project, classes: [container_class, ("limit-container-width" unless fluid_layout)]
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index c7fab87a593..a3688c17041 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -7,9 +7,10 @@
= stylesheet_link_tag 'page_bundles/xterm'
%div{ class: container_class }
- #js-job-vue-app{ data: { endpoint: project_job_path(@project, @build, format: :json),
+ #js-job-vue-app{ data: { endpoint: project_job_path(@project, @build, format: :json), project_path: @project.full_path,
deployment_help_url: help_page_path('user/project/clusters/index.html', anchor: 'troubleshooting-failed-deployment-jobs'),
runner_help_url: help_page_path('ci/runners/README.html', anchor: 'setting-maximum-job-timeout-for-a-runner'),
runner_settings_url: project_runners_path(@build.project, anchor: 'js-runners-settings'),
variables_settings_url: project_variables_path(@build.project, anchor: 'js-cicd-variables-settings'),
+ page_path: project_job_path(@project, @build), build_status: @build.status, build_stage: @build.stage, log_state: '',
build_options: javascript_build_options } }
diff --git a/app/views/projects/services/prometheus/_metrics.html.haml b/app/views/projects/services/prometheus/_metrics.html.haml
index a1d74b91002..3aefb3fdbb9 100644
--- a/app/views/projects/services/prometheus/_metrics.html.haml
+++ b/app/views/projects/services/prometheus/_metrics.html.haml
@@ -1,28 +1,34 @@
- project = local_assigns.fetch(:project)
-.card.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/index') } }
- .card-header
- = s_('PrometheusService|Common metrics')
- %span.badge.badge-pill.js-monitored-count 0
- .card-body
- .loading-metrics.js-loading-metrics
- %p.prepend-top-10.prepend-left-10
- = icon('spinner spin', class: 'metrics-load-spinner')
- = s_('PrometheusService|Finding and configuring metrics...')
- .empty-metrics.hidden.js-empty-metrics
- %p.text-tertiary.prepend-top-10.prepend-left-10
- = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
- %ul.list-unstyled.metrics-list.hidden.js-metrics-list
+.col-lg-3
+ %p
+ = s_('PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters.')
+ = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus_library/index'), target: '_blank', rel: "noopener noreferrer"
-.card.hidden.js-panel-missing-env-vars
- .card-header
- = icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel')
- = s_('PrometheusService|Missing environment variable')
- %span.badge.badge-pill.js-env-var-count 0
- .card-body.hidden
- .flash-container
- .flash-notice
- .flash-text
- = s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries." % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>" }).html_safe
- = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels')
- %ul.list-unstyled.metrics-list.js-missing-var-metrics-list
+.col-lg-9
+ .card.js-panel-monitored-metrics{ data: { active_metrics: active_common_project_prometheus_metrics_path(project, :json), metrics_help_path: help_page_path('user/project/integrations/prometheus_library/index') } }
+ .card-header
+ = s_('PrometheusService|Common metrics')
+ %span.badge.badge-pill.js-monitored-count 0
+ .card-body
+ .loading-metrics.js-loading-metrics
+ %p.prepend-top-10.prepend-left-10
+ = icon('spinner spin', class: 'metrics-load-spinner')
+ = s_('PrometheusService|Finding and configuring metrics...')
+ .empty-metrics.hidden.js-empty-metrics
+ %p.text-tertiary.prepend-top-10.prepend-left-10
+ = s_('PrometheusService|Waiting for your first deployment to an environment to find common metrics')
+ %ul.list-unstyled.metrics-list.hidden.js-metrics-list
+
+ .card.hidden.js-panel-missing-env-vars
+ .card-header
+ = icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel')
+ = s_('PrometheusService|Missing environment variable')
+ %span.badge.badge-pill.js-env-var-count 0
+ .card-body.hidden
+ .flash-container
+ .flash-notice
+ .flash-text
+ = s_("PrometheusService|To set up automatic monitoring, add the environment variable %{variable} to exporter's queries." % { variable: "<code>$CI_ENVIRONMENT_SLUG</code>" }).html_safe
+ = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels')
+ %ul.list-unstyled.metrics-list.js-missing-var-metrics-list
diff --git a/app/views/projects/services/prometheus/_show.html.haml b/app/views/projects/services/prometheus/_show.html.haml
index 6aafa85e99a..c719661d8e8 100644
--- a/app/views/projects/services/prometheus/_show.html.haml
+++ b/app/views/projects/services/prometheus/_show.html.haml
@@ -1,12 +1,9 @@
-.row.prepend-top-default.append-bottom-default.prometheus-metrics-monitoring.js-prometheus-metrics-monitoring
+.row
.col-lg-3
%h4.prepend-top-0
= s_('PrometheusService|Metrics')
- %p
- = s_('PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters.')
- = link_to s_('PrometheusService|More information'), help_page_path('user/project/integrations/prometheus_library/index'), target: '_blank', rel: "noopener noreferrer"
- .col-lg-9
- = render 'projects/services/prometheus/metrics', project: @project
+.row.append-bottom-default.prometheus-metrics-monitoring.js-prometheus-metrics-monitoring
+ = render 'projects/services/prometheus/metrics', project: @project
= render_if_exists 'projects/services/prometheus/external_alerts', project: @project
diff --git a/app/workers/chaos/kill_worker.rb b/app/workers/chaos/kill_worker.rb
index bbad53c9b86..80f04db1be4 100644
--- a/app/workers/chaos/kill_worker.rb
+++ b/app/workers/chaos/kill_worker.rb
@@ -5,6 +5,8 @@ module Chaos
include ApplicationWorker
include ChaosQueue
+ sidekiq_options retry: false
+
def perform
Gitlab::Chaos.kill
end
diff --git a/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml b/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml
new file mode 100644
index 00000000000..adbd7971a14
--- /dev/null
+++ b/changelogs/unreleased/26866-api-endpoint-to-list-the-docker-images-tags-of-a-group.yml
@@ -0,0 +1,6 @@
+---
+title: Add API endpoints to return container repositories and tags from the group
+ level
+merge_request: 30817
+author:
+type: added
diff --git a/changelogs/unreleased/60664-kubernetes-applications-uninstall-cert-manager.yml b/changelogs/unreleased/60664-kubernetes-applications-uninstall-cert-manager.yml
new file mode 100644
index 00000000000..efc3ec241e2
--- /dev/null
+++ b/changelogs/unreleased/60664-kubernetes-applications-uninstall-cert-manager.yml
@@ -0,0 +1,5 @@
+---
+title: Allow Cert-Manager to be uninstalled
+merge_request: 31166
+author:
+type: added
diff --git a/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml b/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml
new file mode 100644
index 00000000000..f35261fcd6c
--- /dev/null
+++ b/changelogs/unreleased/64675-Dashboard-URL-legend-border.yml
@@ -0,0 +1,5 @@
+---
+title: Removed extrenal dashboard legend border
+merge_request: 31407
+author:
+type: fixed
diff --git a/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml b/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml
new file mode 100644
index 00000000000..2a45eec78ef
--- /dev/null
+++ b/changelogs/unreleased/64831-add-padding-to-merged-by-widget.yml
@@ -0,0 +1,5 @@
+---
+title: Add space to "merged by" widget
+merge_request: 30972
+author:
+type: fixed
diff --git a/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml b/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml
new file mode 100644
index 00000000000..4f119d46a1f
--- /dev/null
+++ b/changelogs/unreleased/dblessing-fix-admin-user-radio-labels.yml
@@ -0,0 +1,5 @@
+---
+title: Fix admin area user access level radio button labels
+merge_request: 31154
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-i18n-updated-projects.yml b/changelogs/unreleased/fix-i18n-updated-projects.yml
deleted file mode 100644
index 408ee438480..00000000000
--- a/changelogs/unreleased/fix-i18n-updated-projects.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Properly translate term in projects list
-merge_request: 30958
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml b/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml
new file mode 100644
index 00000000000..7d171c2cf5b
--- /dev/null
+++ b/changelogs/unreleased/fix-name-vs-path-problem-for-cycle-analytics.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken issue links and possible 500 error on cycle analytics page when project name and path are different
+merge_request: 31471
+author:
+type: fixed
diff --git a/changelogs/unreleased/jprovazn-fix-positioning.yml b/changelogs/unreleased/jprovazn-fix-positioning.yml
new file mode 100644
index 00000000000..5d703008bba
--- /dev/null
+++ b/changelogs/unreleased/jprovazn-fix-positioning.yml
@@ -0,0 +1,5 @@
+---
+title: Optimize relative re-positioning when moving issues.
+merge_request: 30938
+author:
+type: fixed
diff --git a/changelogs/unreleased/leipert-improve-ansi2html.yml b/changelogs/unreleased/leipert-improve-ansi2html.yml
deleted file mode 100644
index dd3582b3434..00000000000
--- a/changelogs/unreleased/leipert-improve-ansi2html.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve job log rendering performance
-merge_request: 31262
-author:
-type: performance
diff --git a/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml b/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml
deleted file mode 100644
index 17ff1b012cf..00000000000
--- a/changelogs/unreleased/osw-avoid-errors-due-to-concurrent-calls.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add exclusive lease to mergeability check process
-merge_request: 31082
-author:
-type: fixed
diff --git a/changelogs/unreleased/patch-72.yml b/changelogs/unreleased/patch-72.yml
deleted file mode 100644
index ff2bac2fc29..00000000000
--- a/changelogs/unreleased/patch-72.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Docker in Docker (DIND) listen port behavior change by adding DOCKER_TLS_CERTDIR in CI job templates.
-merge_request: 31201
-author: Cameron Boulton
-type: fixed
diff --git a/changelogs/unreleased/sh-disable-redis-peek.yml b/changelogs/unreleased/sh-disable-redis-peek.yml
new file mode 100644
index 00000000000..de86c0031c7
--- /dev/null
+++ b/changelogs/unreleased/sh-disable-redis-peek.yml
@@ -0,0 +1,5 @@
+---
+title: Only track Redis calls if Peek is enabled
+merge_request: 31438
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-use-redis-caching-store.yml b/changelogs/unreleased/sh-use-redis-caching-store.yml
new file mode 100644
index 00000000000..e61bdb490bc
--- /dev/null
+++ b/changelogs/unreleased/sh-use-redis-caching-store.yml
@@ -0,0 +1,5 @@
+---
+title: Use Rails 5.2 Redis caching store
+merge_request: 30966
+author:
+type: other
diff --git a/changelogs/unreleased/update-pipelines-minutes-expiry-banner-to-an-alert-component-type.yml b/changelogs/unreleased/update-pipelines-minutes-expiry-banner-to-an-alert-component-type.yml
new file mode 100644
index 00000000000..8c1a033dd29
--- /dev/null
+++ b/changelogs/unreleased/update-pipelines-minutes-expiry-banner-to-an-alert-component-type.yml
@@ -0,0 +1,5 @@
+---
+title: Enhance style of the shared runners limit
+merge_request: 31386
+author:
+type: other
diff --git a/config/application.rb b/config/application.rb
index 92240426b5a..21cb79f7851 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -233,7 +233,10 @@ module Gitlab
end
# Use caching across all environments
+ # Full list of options:
+ # https://api.rubyonrails.org/classes/ActiveSupport/Cache/RedisCacheStore.html#method-c-new
caching_config_hash = Gitlab::Redis::Cache.params
+ caching_config_hash[:compress] = false
caching_config_hash[:namespace] = Gitlab::Redis::Cache::CACHE_NAMESPACE
caching_config_hash[:expires_in] = 2.weeks # Cache should not grow forever
if Sidekiq.server? # threaded context
@@ -241,7 +244,7 @@ module Gitlab
caching_config_hash[:pool_timeout] = 1
end
- config.cache_store = :redis_store, caching_config_hash
+ config.cache_store = :redis_cache_store, caching_config_hash
config.active_job.queue_adapter = :sidekiq
diff --git a/db/migrate/20190802012622_reorder_issues_project_id_relative_position_index.rb b/db/migrate/20190802012622_reorder_issues_project_id_relative_position_index.rb
new file mode 100644
index 00000000000..12088dd763f
--- /dev/null
+++ b/db/migrate/20190802012622_reorder_issues_project_id_relative_position_index.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class ReorderIssuesProjectIdRelativePositionIndex < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ OLD_INDEX_NAME = 'index_issues_on_project_id_and_state_and_rel_position_and_id'
+ NEW_INDEX_NAME = 'index_issues_on_project_id_and_rel_position_and_state_and_id'
+
+ def up
+ add_concurrent_index :issues, [:project_id, :relative_position, :state, :id], order: { id: :desc }, name: NEW_INDEX_NAME
+
+ remove_concurrent_index_by_name :issues, OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :issues, [:project_id, :state, :relative_position, :id], order: { id: :desc }, name: OLD_INDEX_NAME
+
+ remove_concurrent_index_by_name :issues, NEW_INDEX_NAME
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index fe3fa597006..a9b7c1930e3 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2019_08_01_114109) do
+ActiveRecord::Schema.define(version: 2019_08_02_012622) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -1716,7 +1716,7 @@ ActiveRecord::Schema.define(version: 2019_08_01_114109) do
t.index ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state"
t.index ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)"
t.index ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true
- t.index ["project_id", "state", "relative_position", "id"], name: "index_issues_on_project_id_and_state_and_rel_position_and_id", order: { id: :desc }
+ t.index ["project_id", "relative_position", "state", "id"], name: "index_issues_on_project_id_and_rel_position_and_state_and_id", order: { id: :desc }
t.index ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state"
t.index ["relative_position"], name: "index_issues_on_relative_position"
t.index ["state"], name: "index_issues_on_state"
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index f6f02221fe3..150494c47e5 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -36,13 +36,18 @@ installations will be better served with the default configuration
used by Omnibus and the GitLab source installation guide.
Starting with GitLab 11.4, Gitaly is able to serve all Git requests without
-needed a shared NFS mount for Git repository data.
+requiring a shared NFS mount for Git repository data.
Between 11.4 and 11.8 the exception was the
[Elasticsearch indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer).
But since 11.8 the indexer uses Gitaly for data access as well. NFS can still
be leveraged for redudancy on block level of the Git data. But only has to
be mounted on the Gitaly server.
+Starting with GitLab 11.8, it is possible to use ElasticSearch in conjunction with
+a Gitaly setup that isn't utilising NFS. In order to use ElasticSearch in this
+scenario, the [new repository indexer](../../integration/elasticsearch.md#elasticsearch-repository-indexer-beta)
+needs to be enabled in your GitLab configuration.
+
NOTE: **Note:** While Gitaly can be used as a replacement for NFS, it's not recommended
to use EFS as it may impact GitLab's performance. Review the [relevant documentation](../high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs)
for more details.
@@ -469,7 +474,16 @@ One current feature of GitLab that still requires a shared directory (NFS) is
There is [work in progress](https://gitlab.com/gitlab-org/gitlab-pages/issues/196)
to eliminate the need for NFS to support GitLab Pages.
-## Troubleshooting
+## Troubleshooting Gitaly
+
+### Commits, pushes, and clones return a 401
+
+```
+remote: GitLab: 401 Unauthorized
+```
+
+You will need to sync your `gitlab-secrets.json` file with your GitLab
+app nodes.
### `gitaly-debug`
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 00c8863f200..f7f9d753e58 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -185,3 +185,6 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Debugging tips](troubleshooting/debug.md): Tips to debug problems when things go wrong
- [Log system](logs.md): Where to look for logs.
- [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs.
+- Useful [diagnostics tools](troubleshooting/diagnostics_tools.md) that are sometimes used by the GitLab
+ Support team.
+- [Troubleshooting ElasticSearch](troubleshooting/elasticsearch.md): Tips to troubleshoot ElasticSearch.
diff --git a/doc/administration/plugins.md b/doc/administration/plugins.md
index 4302667caf5..4cf3c607dae 100644
--- a/doc/administration/plugins.md
+++ b/doc/administration/plugins.md
@@ -52,7 +52,37 @@ as appropriate. The plugins file list is updated for each event, there is no
need to restart GitLab to apply a new plugin.
If a plugin executes with non-zero exit code or GitLab fails to execute it, a
-message will be logged to `plugin.log`.
+message will be logged to:
+
+- `gitlab-rails/plugin.log` in an Omnibus installation.
+- `log/plugin.log` in a source installation.
+
+## Creating plugins
+
+Below is an example that will only response on the event `project_create` and
+will inform the admins from the GitLab instance that a new project has been created.
+
+```ruby
+# By using the embedded ruby version we eliminate the possibility that our chosen language
+# would be unavailable from
+#!/opt/gitlab/embedded/bin/ruby
+require 'json'
+require 'mail'
+
+# The incoming variables are in JSON format so we need to parse it first.
+ARGS = JSON.parse(STDIN.read)
+
+# We only want to trigger this plugin on the event project_create
+return unless ARGS['event_name'] == 'project_create'
+
+# We will inform our admins of our gitlab instance that a new project is created
+Mail.deliver do
+ from 'info@gitlab_instance.com'
+ to 'admin@gitlab_instance.com'
+ subject "new project " + ARGS['name']
+ body ARGS['owner_name'] + 'created project ' + ARGS['name']
+end
+```
## Validation
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index ad3a9b19c3c..b1a870210a8 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -57,10 +57,10 @@ storage2:
Now that you've read that big fat warning above, let's edit the configuration
files and add the full paths of the alternative repository storage paths. In
-the example below, we add two more mountpoints that are named `nfs` and `cephfs`
+the example below, we add two more mountpoints that are named `nfs_1` and `nfs_2`
respectively.
-NOTE: **Note:** This example uses NFS and CephFS. We do not recommend using EFS for storage as it may impact GitLab's performance. See the [relevant documentation](high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details.
+NOTE: **Note:** This example uses NFS. We do not recommend using EFS for storage as it may impact GitLab's performance. See the [relevant documentation](high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details.
**For installations from source**
@@ -73,10 +73,10 @@ NOTE: **Note:** This example uses NFS and CephFS. We do not recommend using EFS
storages: # You must have at least a 'default' storage path.
default:
path: /home/git/repositories
- nfs:
- path: /mnt/nfs/repositories
- cephfs:
- path: /mnt/cephfs/repositories
+ nfs_1:
+ path: /mnt/nfs1/repositories
+ nfs_2:
+ path: /mnt/nfs2/repositories
```
1. [Restart GitLab][restart-gitlab] for the changes to take effect.
@@ -96,8 +96,8 @@ working, you can remove the `repos_path` line.
```ruby
git_data_dirs({
"default" => { "path" => "/var/opt/gitlab/git-data" },
- "nfs" => { "path" => "/mnt/nfs/git-data" },
- "cephfs" => { "path" => "/mnt/cephfs/git-data" }
+ "nfs_1" => { "path" => "/mnt/nfs1/git-data" },
+ "nfs_2" => { "path" => "/mnt/nfs2/git-data" }
})
```
diff --git a/doc/administration/troubleshooting/diagnostics_tools.md b/doc/administration/troubleshooting/diagnostics_tools.md
new file mode 100644
index 00000000000..ab3b25f0e97
--- /dev/null
+++ b/doc/administration/troubleshooting/diagnostics_tools.md
@@ -0,0 +1,27 @@
+---
+type: reference
+---
+
+# Diagnostics tools
+
+These are some of the diagnostics tools the GitLab Support team uses during troubleshooting.
+They are listed here for transparency, and they may be useful for users with experience
+with troubleshooting GitLab. If you are currently having an issue with GitLab, you
+may want to check your [support options](https://about.gitlab.com/support/) first,
+before attempting to use these tools.
+
+## gitlabsos
+
+The [gitlabsos](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/) utility
+provides a unified method of gathering info and logs from GitLab and the system it's
+running on.
+
+## strace-parser
+
+[strace-parser](https://gitlab.com/wchandler/strace-parser) is a small tool to analyze
+and summarize raw strace data.
+
+## Pritaly
+
+[Pritaly](https://gitlab.com/wchandler/pritaly) takes Gitaly logs and colorizes output
+or converts the logs to JSON.
diff --git a/doc/administration/troubleshooting/elasticsearch.md b/doc/administration/troubleshooting/elasticsearch.md
new file mode 100644
index 00000000000..c4a7ba01fae
--- /dev/null
+++ b/doc/administration/troubleshooting/elasticsearch.md
@@ -0,0 +1,345 @@
+# Troubleshooting ElasticSearch
+
+Troubleshooting ElasticSearch requires:
+
+- Knowledge of common terms.
+- Establishing within which category the problem fits.
+
+## Common terminology
+
+- **Lucene**: A full-text search library written in Java.
+- **Near Realtime (NRT)**: Refers to the slight latency from the time to index a
+ document to the time when it becomes searchable.
+- **Cluster**: A collection of one or more nodes that work together to hold all
+ the data, providing indexing and search capabilities.
+- **Node**: A single server that works as part of a cluster.
+- **Index**: A collection of documents that have somewhat similar characteristics.
+- **Document**: A basic unit of information that can be indexed.
+- **Shards**: Fully-functional and independent subdivisions of indices. Each shard is actually
+ a Lucene index.
+- **Replicas**: Failover mechanisms that duplicate indices.
+
+## Troubleshooting workflows
+
+The type of problem will determine what steps to take. The possible troubleshooting workflows are for:
+
+- Search results.
+- Indexing.
+- Integration.
+- Performance.
+
+### Search Results workflow
+
+The following workflow is for ElasticSearch search results issues:
+
+```mermaid
+graph TD;
+ B --> |No| B1
+ B --> |Yes| B4
+ B1 --> B2
+ B2 --> B3
+ B4 --> B5
+ B5 --> |Yes| B6
+ B5 --> |No| B7
+ B7 --> B8
+ B{Is GitLab using<br>ElasticSearch for<br>searching?}
+ B1[Check Admin Area > Integrations<br>to ensure the settings are correct]
+ B2[Perform a search via<br>the rails console]
+ B3[If all settings are correct<br>and it still doesn't show ElasticSearch<br>doing the searches, escalate<br>to GitLab support.]
+ B4[Perform<br>the same search via the<br>ElasticSearch API]
+ B5{Are the results<br>the same?}
+ B6[This means it is working as intended.<br>Speak with GitLab support<br>to confirm if the issue lies with<br>the filters.]
+ B7[Check the index status of the project<br>containing the missing search<br>results.]
+ B8(Indexing Troubleshooting)
+```
+
+### Indexing workflow
+
+The following workflow is for ElasticSearch indexing issues:
+
+```mermaid
+graph TD;
+ C --> |Yes| C1
+ C1 --> |Yes| C2
+ C1 --> |No| C3
+ C3 --> |Yes| C4
+ C3 --> |No| C5
+ C --> |No| C6
+ C6 --> |No| C10
+ C7 --> |GitLab| C8
+ C7 --> |ElasticSearch| C9
+ C6 --> |Yes| C7
+ C10 --> |No| C12
+ C10 --> |Yes| C11
+ C12 --> |Yes| C13
+ C12 --> |No| C14
+ C14 --> |Yes| C15
+ C14 --> |No| C16
+ C{Is the problem with<br>creating an empty<br>index?}
+ C1{Does the gitlab-production<br>index exist on the<br>ElasticSearch instance?}
+ C2(Try to manually<br>delete the index on the<br>ElasticSearch instance and<br>retry creating an empty index.)
+ C3{Can indices be made<br>manually on the ElasticSearch<br>instance?}
+ C4(Retry the creation of an empty index)
+ C5(It is best to speak with an<br>ElasticSearch admin concerning the<br>instance's inability to create indices.)
+ C6{Is the indexer presenting<br>errors during indexing?}
+ C7{Is the error a GitLab<br>error or an ElasticSearch<br>error?}
+ C8[Escalate to<br>GitLab support]
+ C9[You will want<br>to speak with an<br>ElasticSearch admin.]
+ C10{Does the index status<br>show 100%?}
+ C11[Escalate to<br>GitLab support]
+ C12{Does re-indexing the project<br> present any GitLab errors?}
+ C13[Rectify the GitLab errors and<br>restart troubleshooting, or<br>escalate to GitLab support.]
+ C14{Does re-indexing the project<br>present errors on the <br>ElasticSearch instance?}
+ C15[It would be best<br>to speak with an<br>ElasticSearch admin.]
+ C16[This is likely a bug/issue<br>in GitLab and will require<br>deeper investigation. Escalate<br>to GitLab support.]
+```
+
+### Integration workflow
+
+The following workflow is for ElasticSearch integration issues:
+
+```mermaid
+graph TD;
+ D --> |No| D1
+ D --> |Yes| D2
+ D2 --> |No| D3
+ D2 --> |Yes| D4
+ D4 --> |No| D5
+ D4 --> |Yes| D6
+ D{Is the error concerning<br>the beta indexer?}
+ D1[It would be best<br>to speak with an<br>ElasticSearch admin.]
+ D2{Is the ICU development<br>package installed?}
+ D3>This package is required.<br>Install the package<br>and retry.]
+ D4{Is the error stemming<br>from the indexer?}
+ D5[This would indicate an OS level<br> issue. It would be best to<br>contact your sysadmin.]
+ D6[This is likely a bug/issue<br>in GitLab and will require<br>deeper investigation. Escalate<br>to GitLab support.]
+```
+
+### Performance workflow
+
+The following workflow is for ElasticSearch performance issues:
+
+```mermaid
+graph TD;
+ F --> |Yes| F1
+ F --> |No| F2
+ F2 --> |No| F3
+ F2 --> |Yes| F4
+ F4 --> F5
+ F5 --> |No| F6
+ F5 --> |Yes| F7
+ F{Is the ElasticSearch instance<br>running on the same server<br>as the GitLab instance?}
+ F1(This is not advised and will cause issues.<br>We recommend moving the ElasticSearch<br>instance to a different server.)
+ F2{Does the ElasticSearch<br>server have at least 8<br>GB of RAM and 2 CPU<br>cores?}
+ F3(According to ElasticSearch, a non-prod<br>server needs these as a base requirement.<br>Production often requires more. We recommend<br>you increase the server specifications.)
+ F4(Obtain the <br>cluster health information)
+ F5(Does it show the<br>status as green?)
+ F6(We recommend you speak with<br>an ElasticSearch admin<br>about implementing sharding.)
+ F7(Escalate to<br>GitLab support.)
+```
+
+## Troubleshooting walkthrough
+
+Most ElasticSearch troubleshooting can be broken down into 4 categories:
+
+- [Troubleshooting search results](#troubleshooting-search-results)
+- [Troubleshooting indexing](#troubleshooting-indexing)
+- [Troubleshooting integration](#troubleshooting-integration)
+- [Troubleshooting performance](#troubleshooting-performance)
+
+Generally speaking, if it does not fall into those four categories, it is either:
+
+- Something GitLab support needs to look into.
+- Not a true ElasticSearch issue.
+
+Exercise caution. Issues that appear to be ElasticSearch problems can be OS-level issues.
+
+### Troubleshooting search results
+
+Troubleshooting search result issues is rather straight forward on ElasticSearch.
+
+The first step is to confirm GitLab is using ElasticSearch for the search function.
+To do this:
+
+1. Confirm the integration is enabled in **Admin Area > Settings > Integrations**.
+1. Confirm searches utilize ElasticSearch by accessing the rails console
+ (`sudo gitlab-rails console`) and running the following commands:
+
+ ```rails
+ u = User.find_by_email('email_of_user_doing_search')
+ s = SearchService.new(u, {:search => 'search_term'})
+ pp s.search_objects.class.name
+ ```
+
+The ouput from the last command is the key here. If it shows:
+
+- `ActiveRecord::Relation`, **it is not** using ElasticSearch.
+- `Kaminari::PaginatableArray`, **it is** using ElasticSearch.
+
+| Not using ElasticSearch | Using ElasticSearch |
+|--------------------------|------------------------------|
+| `ActiveRecord::Relation` | `Kaminari::PaginatableArray` |
+
+If all the settings look correct and it is still not using ElasticSearch for the search function, it is best to escalate to GitLab support. This could be a bug/issue.
+
+Moving past that, it is best to attempt the same search using the [ElasticSearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) and compare the results from what you see in GitLab.
+
+If the results:
+
+- Sync up, then there is not a technical "issue" per se. Instead, it might be a problem
+ with the ElasticSearch filters we are using. This can be complicated, so it is best to
+ escalate to GitLab support to check these and guide you on the potential on whether or
+ not a feature request is needed.
+- Do not match up, this indicates a problem with the documents generated from the
+ project. It is best to re-index that project and proceed with
+ [Troubleshooting indexing](#troubleshooting-indexing).
+
+### Troubleshooting indexing
+
+Troubleshooting indexing issues can be tricky. It can pretty quickly go to either GitLab
+support or your ElasticSearch admin.
+
+The best place to start is to determine if the issue is with creating an empty index.
+If it is, check on the ElasticSearch side to determine if the `gitlab-production` (the
+name for the GitLab index) exists. If it exists, manually delete it on the ElasticSearch
+side and attempt to recreate it from the
+[`create_empty_index`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks)
+rake task.
+
+If you still encounter issues, try creating an index manually on the ElasticSearch
+instance. The details of the index aren't important here, as we want to test if indices
+can be made. If the indices:
+
+- Cannot be made, speak with your ElasticSearch admin.
+- Can be made, Escalate this to GitLab support.
+
+If the issue is not with creating an empty index, the next step is to check for errors
+during the indexing of projects. If errors do occur, they will either stem from the indexing:
+
+- On the GitLab side. You need to rectify those. If they are not
+ something you are familiar with, contact GitLab support for guidance.
+- Within the ElasticSearch instance itself. See if the error is [documented and has a fix](../../integration/elasticsearch.md#troubleshooting). If not, speak with your ElasticSearch admin.
+
+If the indexing process does not present errors, you will want to check the status of the indexed projects. You can do this via the following rake tasks:
+
+- [`sudo gitlab-rake gitlab:elastic:index_projects_status`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) (shows the overall status)
+- [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) (shows specific projects that are not indexed)
+
+If:
+
+- Everything is showing at 100%, escalate to GitLab support. This could be a potential
+ bug/issue.
+- You do see something not at 100%, attempt to reindex that project. To do this,
+ run `sudo gitlab-rake gitlab:elastic:index_projects ID_FROM=<project ID> ID_TO=<project ID>`.
+
+If reindexing the project shows:
+
+- Errors on the GitLab side, escalate those to GitLab support.
+- ElasticSearch errors or doesn't present any errors at all, reach out to your
+ ElasticSearch admin to check the instance.
+
+### Troubleshooting integration
+
+Troubleshooting integration tends to be pretty straight forward, as there really isn't
+much to "integrate" here.
+
+If the issue is:
+
+- Not concerning the beta indexer, it is almost always an
+ ElasticSearch-side issue. This means you should reach out to your ElasticSearch admin
+ regarding the error(s) you are seeing. If you are unsure here, it never hurts to reach
+ out to GitLab support.
+- With the beta indexer, check if the ICU development package is installed.
+ This is a required package so make sure you install it.
+
+Beyond that, you will want to review the error. If it is:
+
+- Specifically from the indexer, this could be a bug/issue and should be escalated to
+ GitLab support.
+- An OS issue, you will want to reach out to your systems administrator.
+
+### Troubleshooting performance
+
+Troubleshooting performance can be difficult on ElasticSearch. There is a ton of tuning
+that *can* be done, but the majority of this falls on shoulders of a skilled
+ElasticSearch administrator.
+
+Generally speaking, ensure:
+
+* The ElasticSearch server **is not** running on the same node as GitLab.
+* The ElasticSearch server have enough RAM and CPU cores.
+* That sharding **is** being used.
+
+Going into some more detail here, if ElasticSearch is running on the same server as GitLab, resource contention is **very** likely to occur. Ideally, ElasticSearch, which requires ample resources, should be running on its own server (maybe coupled with logstash and kibana).
+
+When it comes to ElasticSearch, RAM is the key resource. ElasticSearch themselves recommend:
+
+- **At least** 8 GB of RAM for a non-production instance.
+- **At least** 16 GB of RAM for a production instance.
+- Ideally, 64 GB of RAM.
+
+For CPU, ElasticSearch recommends at least 2 CPU cores, but ElasticSearch states common
+setups use up to 8 cores. For more details on server specs, check out
+[ElasticSearch's hardware guide](https://www.elastic.co/guide/en/elasticsearch/guide/current/hardware.html).
+
+Beyond the obvious, sharding comes into play. Sharding is a core part of ElasticSearch.
+It allows for horizontal scaling of indices, which is helpful when you are dealing with
+a large amount of data.
+
+With the way GitLab does indexing, there is a **huge** amount of documents being
+indexed. By utilizing sharding, you can speed up ElasticSearch's ability to locate
+data, since each shard is a Lucene index.
+
+If you are not using sharding, you are likely to hit issues when you start using
+ElasticSearch in a production environment.
+
+Keep in mind that an index with only one shard has **no scale factor** and will
+likely encounter issues when called upon with some frequency.
+
+If you need to know how many shards, read
+[ElasticSearch's documentation on capacity planning](https://www.elastic.co/guide/en/elasticsearch/guide/2.x/capacity-planning.html),
+as the answer is not straight forward.
+
+The easiest way to determine if sharding is in use is to check the output of the
+[ElasticSearch Health API](https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-health.html):
+
+- Red means the cluster is down.
+- Yellow means it is up with no sharding/replication.
+- Green means it is healthy (up, sharding, replicating).
+
+For production use, it should always be green.
+
+Beyond these steps, you get into some of the more complicated things to check,
+such as merges and caching. These can get complicated and it takes some time to
+learn them, so it is best to escalate/pair with an ElasticSearch expert if you need to
+dig further into these.
+
+Feel free to reach out to GitLab support, but this is likely to be something a skilled
+ElasticSearch admin has more experience with.
+
+## Common issues
+
+All common issues [should be documented](../../integration/elasticsearch.md#troubleshooting). If not,
+feel free to update that page with issues you encounter and solutions.
+
+## Replication
+
+Setting up ElasticSearch isn't too bad, but it can be a bit finnicky and time consuming.
+
+The eastiest method is to spin up a docker container with the required version and
+bind ports 9200/9300 so it can be used.
+
+The following is an example of running a docker container of ElasticSearch v7.2.0:
+
+```bash
+docker pull docker.elastic.co/elasticsearch/elasticsearch:7.2.0
+docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.2.0
+```
+
+From here, you can:
+
+- Grab the IP of the docker container (use `docker inspect <container_id>`)
+- Use `<IP.add.re.ss:9200>` to communicate with it.
+
+This is a quick method to test out ElasticSearch, but by no means is this a
+production solution.
diff --git a/doc/api/container_registry.md b/doc/api/container_registry.md
index 174b93a4f7a..bf544f64178 100644
--- a/doc/api/container_registry.md
+++ b/doc/api/container_registry.md
@@ -6,6 +6,8 @@ This is the API docs of the [GitLab Container Registry](../user/project/containe
## List registry repositories
+### Within a project
+
Get a list of registry repositories in a project.
```
@@ -14,7 +16,8 @@ GET /projects/:id/registry/repositories
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
+| `tags` | boolean | no | If the param is included as true, each repository will include an array of `"tags"` in the response. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories"
@@ -28,6 +31,7 @@ Example response:
"id": 1,
"name": "",
"path": "group/project",
+ "project_id": 9,
"location": "gitlab.example.com:5000/group/project",
"created_at": "2019-01-10T13:38:57.391Z"
},
@@ -35,12 +39,77 @@ Example response:
"id": 2,
"name": "releases",
"path": "group/project/releases",
+ "project_id": 9,
"location": "gitlab.example.com:5000/group/project/releases",
"created_at": "2019-01-10T13:39:08.229Z"
}
]
```
+### Within a group
+
+Get a list of registry repositories in a group.
+
+```
+GET /groups/:id/registry/repositories
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
+| `tags` | boolean | no | If the param is included as true, each repository will include an array of `"tags"` in the response. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "",
+ "path": "group/project",
+ "project_id": 9,
+ "location": "gitlab.example.com:5000/group/project",
+ "created_at": "2019-01-10T13:38:57.391Z",
+ "tags": [
+ {
+ "name": "0.0.1",
+ "path": "group/project:0.0.1",
+ "location": "gitlab.example.com:5000/group/project:0.0.1"
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "name": "",
+ "path": "group/other_project",
+ "project_id": 11,
+ "location": "gitlab.example.com:5000/group/other_project",
+ "created_at": "2019-01-10T13:39:08.229Z",
+ "tags": [
+ {
+ "name": "0.0.1",
+ "path": "group/other_project:0.0.1",
+ "location": "gitlab.example.com:5000/group/other_project:0.0.1"
+ },
+ {
+ "name": "0.0.2",
+ "path": "group/other_project:0.0.2",
+ "location": "gitlab.example.com:5000/group/other_project:0.0.2"
+ },
+ {
+ "name": "latest",
+ "path": "group/other_project:latest",
+ "location": "gitlab.example.com:5000/group/other_project:latest"
+ }
+ ]
+ }
+]
+```
+
## Delete registry repository
Delete a repository in registry.
@@ -62,6 +131,8 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
## List repository tags
+### Within a project
+
Get a list of tags for given registry repository.
```
@@ -70,7 +141,7 @@ GET /projects/:id/registry/repositories/:repository_id/tags
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `repository_id` | integer | yes | The ID of registry repository. |
```bash
@@ -104,7 +175,7 @@ GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `repository_id` | integer | yes | The ID of registry repository. |
| `tag_name` | string | yes | The name of tag. |
diff --git a/doc/customization/branded_login_page.md b/doc/customization/branded_login_page.md
index b892f59d777..afcc2b71284 100644
--- a/doc/customization/branded_login_page.md
+++ b/doc/customization/branded_login_page.md
@@ -1,19 +1,38 @@
-# Changing the appearance of the login page
+---
+type: howto
+---
-GitLab offers a way to put your company's identity on the login page of your GitLab server and make it a branded login page.
+# Changing the logo and description on the login page
-By default, the page shows the GitLab logo and description.
+You can customize the login page of your GitLab server to show the logo and
+description of your organization.
+
+By default, the page shows the GitLab logo and description:
![default_login_page](branded_login_page/default_login_page.png)
-## Changing the appearance of the login page
+To customize the login page:
-Navigate to the **Admin** area and go to the **Appearance** page.
+1. Navigate to the **Admin** area and go to the **Appearance** page.
+1. Fill in your desired Title and Description. You can also choose an image file
+ of the logo for your organization.
-Fill in the required details like Title, Description and upload the company logo.
+ ![appearance](branded_login_page/appearance.png)
-![appearance](branded_login_page/appearance.png)
+1. Save your changes.
-After saving the page, your GitLab login page will have the details you filled in:
+Your GitLab login page will display the details you provided:
![company_login_page](branded_login_page/custom_sign_in.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/customization/branded_page_and_email_header.md b/doc/customization/branded_page_and_email_header.md
index 9a0f0b382fa..370c1461d30 100644
--- a/doc/customization/branded_page_and_email_header.md
+++ b/doc/customization/branded_page_and_email_header.md
@@ -1,15 +1,37 @@
-# Changing the logo on the overall page and email header
+---
+type: howto
+---
-Navigate to the **Admin** area and go to the **Appearance** page.
+# Changing the navigation bar and email header logo
-Upload the custom logo (**Header logo**) in the section **Navigation bar**.
+You can customize the logo that appears in email headers and in the navigation
+bar on pages that are displayed by your GitLab server.
-![appearance](branded_page_and_email_header/appearance.png)
+1. Navigate to the **Admin** area and go to the **Appearance** page, then locate
+ the **Navigation bar** section.
+1. For the **Header Logo**, choose an image file of the logo for your
+ organization.
-After saving the page, your GitLab navigation bar will contain the custom logo:
+ ![appearance](branded_page_and_email_header/appearance.png)
+
+1. Save your changes.
+
+Your GitLab navigation bar will display the custom logo:
![custom_brand_header](branded_page_and_email_header/custom_brand_header.png)
-The GitLab pipeline emails will also have the custom logo:
+The GitLab pipeline emails will also display the custom logo:
![custom_email_header](branded_page_and_email_header/custom_email_header.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/customization/favicon.md b/doc/customization/favicon.md
index 45a18159b5e..dbde6e8c03b 100644
--- a/doc/customization/favicon.md
+++ b/doc/customization/favicon.md
@@ -1,16 +1,37 @@
+---
+type: howto
+---
+
# Changing the favicon
> [Introduced][ce-14497] in GitLab 11.0.
[ce-14497]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14497
-Navigate to the **Admin** area and go to the **Appearance** page.
+You can customize the favicon (the icon displayed in your web browser's
+address bar and web page tabs) for your GitLab server.
+
+1. Navigate to the **Admin** area and go to the **Appearance** page, then
+ locate the **Favicon** section.
+1. Upload an image file of your favicon.
-Upload the custom favicon (**Favicon**) in the section **Favicon**.
+ ![appearance](favicon/appearance.png)
-![appearance](favicon/appearance.png)
+1. Save your changes.
-After saving the page, the new favicon will be shown in the browser. The main
-favicon as well as the CI status icons will show the custom icon:
+Your new favicon will display in the browser. The main favicon and the CI
+status icons will show the custom icon:
![custom_favicon](favicon/custom_favicon.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/customization/help_message.md b/doc/customization/help_message.md
index c2e592d03bf..a4d8f295750 100644
--- a/doc/customization/help_message.md
+++ b/doc/customization/help_message.md
@@ -1,13 +1,36 @@
-# GitLab Help custom text
+---
+type: howto
+---
-In larger organizations it is useful to have information about who has the responsibility of maintaining the company GitLab server.
+# Customizing the 'Help' and login page messages
-1. Navigate to the admin area, click on **Preferences** and expand **Help page**.
+In large organizations, it is useful to have information about who maintains
+the company GitLab server. You can customize and display this information on
+the GitLab login page and on the GitLab server's `/help` page.
-1. Under **Help text** fill in the required information about the person(s) administering GitLab or any other information relevant to your needs.
+1. Navigate to the **Admin** area, then click on **Preferences** and expand
+ **Help page**.
+1. Under **Help page text**, fill in the required information about the
+ person(s) administering GitLab. This text can also contain any other
+ information that you wish to display to users.
- ![help message](help_message/help_text.png)
+ ![help message](help_message/help_text.png)
-1. After saving the page this information will be shown on the GitLab login page and on the GitLab `/help` page (e.g., <https://gitlab.com/help>).
+1. Save your changes.
- ![help text on help page](help_message/help_text_on_help_page.png)
+The information you entered will be shown on the GitLab login page and on the
+GitLab `/help` page (e.g., <https://gitlab.com/help>).
+
+![help text on help page](help_message/help_text_on_help_page.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/customization/index.md b/doc/customization/index.md
index 0198059297f..f17a2d80e2c 100644
--- a/doc/customization/index.md
+++ b/doc/customization/index.md
@@ -1,18 +1,18 @@
---
+type: index
description: Learn how to customize GitLab's appearance for self-managed installations.
---
# Customizing GitLab's appearance **(CORE ONLY)**
-For GitLab self-managed instances, it's possible to customize
-a few pages.
+For GitLab self-managed instances, you can customize the page logo,
+email headers, favicon, and several other aspects of GitLab's appearance.
-Read through the following documents to adjust GitLab's
-look and feel to meet your needs:
+The following pages explain how to customize the appearance of your instance:
-- [Custom login page](branded_login_page.md)
-- [Custom header and email logo](branded_page_and_email_header.md)
-- [Custom favicon](favicon.md)
-- [Libravatar](libravatar.md)
-- [New project page](new_project_page.md)
-- [Custom `/help` message](help_message.md) \ No newline at end of file
+- [Changing the logo and description on the login page](branded_login_page.md)
+- [Changing the navigation bar and email header logo](branded_page_and_email_header.md)
+- [Changing the favicon](favicon.md)
+- [Customizing the new project page](new_project_page.md)
+- [Customizing the `/help` and login page messages](help_message.md)
+- [Using the Libravatar service with GitLab](libravatar.md)
diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md
index e618f3be2fe..1c3bf877fa1 100644
--- a/doc/customization/libravatar.md
+++ b/doc/customization/libravatar.md
@@ -1,14 +1,20 @@
-# Use Libravatar service with GitLab
+---
+type: howto
+---
-GitLab by default supports [Gravatar](https://gravatar.com) avatar service.
-Libravatar is a service which delivers your avatar (profile picture) to other websites and their API is
-[heavily based on gravatar](https://wiki.libravatar.org/api/).
+# Using the Libravatar service with GitLab
-This means that it is not complicated to switch to Libravatar avatar service or even self hosted Libravatar server.
+GitLab by default supports the [Gravatar](https://gravatar.com) avatar service.
+
+Libravatar is another service that delivers your avatar (profile picture) to
+other websites. The Libravatar API is
+[heavily based on gravatar](https://wiki.libravatar.org/api/), so you can
+easily switch to the Libravatar avatar service or even a self-hosted Libravatar
+server.
## Configuration
-In [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122) set
+In the [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122), set
the configuration options as follows:
### For HTTP
@@ -29,12 +35,14 @@ the configuration options as follows:
ssl_url: "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
```
-### Self-hosted
+### Self-hosted Libravatar server
-If you are [running your own libravatar service](https://wiki.libravatar.org/running_your_own/) the URL will be different in the configuration
-but the important part is to provide the same placeholders so GitLab can parse the URL correctly.
+If you are [running your own libravatar service](https://wiki.libravatar.org/running_your_own/),
+the URL will be different in the configuration, but you must provide the same
+placeholders so GitLab can parse the URL correctly.
-For example, you host a service on `http://libravatar.example.com` the `plain_url` you need to supply in `gitlab.yml` is
+For example, you host a service on `http://libravatar.example.com` and the
+`plain_url` you need to supply in `gitlab.yml` is
`http://libravatar.example.com/avatar/%{hash}?s=%{size}&d=identicon`
@@ -42,37 +50,52 @@ For example, you host a service on `http://libravatar.example.com` the `plain_ur
In `/etc/gitlab/gitlab.rb`:
-#### For http
+#### For HTTP
```ruby
gitlab_rails['gravatar_enabled'] = true
gitlab_rails['gravatar_plain_url'] = "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
```
-#### For https
+#### For HTTPS
```ruby
gitlab_rails['gravatar_enabled'] = true
gitlab_rails['gravatar_ssl_url'] = "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
```
-Run `sudo gitlab-ctl reconfigure` for changes to take effect.
+Then run `sudo gitlab-ctl reconfigure` for the changes to take effect.
## Default URL for missing images
-[Libravatar supports different sets](https://wiki.libravatar.org/api/) of `missing images` for emails not found on the Libravatar service.
-
-In order to use a different set other than `identicon`, replace `&d=identicon` portion of the URL with another supported set.
-For example, you can use `retro` set in which case the URL would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
+[Libravatar supports different sets](https://wiki.libravatar.org/api/) of
+missing images for user email addresses that are not found on the Libravatar
+service.
-## Usage examples
+In order to use a set other than `identicon`, replace the `&d=identicon`
+portion of the URL with another supported set.
+For example, you can use the `retro` set, in which case the URL would look like:
+`plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
-### For Microsoft Office 365
+## Usage examples for Microsoft Office 365
-If your users are Office 365-users, the "GetPersonaPhoto" service can be used. Note that this service requires login, so this use case is
-most useful in a corporate installation, where all users have access to Office 365.
+If your users are Office 365 users, the `GetPersonaPhoto` service can be used.
+Note that this service requires a login, so this use case is most useful in a
+corporate installation where all users have access to Office 365.
```ruby
gitlab_rails['gravatar_plain_url'] = 'http://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
gitlab_rails['gravatar_ssl_url'] = 'https://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
```
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/customization/new_project_page.md b/doc/customization/new_project_page.md
index 148bf9512c6..43b95a76d08 100644
--- a/doc/customization/new_project_page.md
+++ b/doc/customization/new_project_page.md
@@ -1,20 +1,38 @@
+---
+type: howto
+---
+
# Customizing the new project page
-It is possible to add a markdown-formatted message to your GitLab
-new project page.
+You can add a markdown-formatted message to your GitLab new project page.
By default, the new project page shows a sidebar with general information:
-![](new_project_page/default_new_project_page.png)
+![default_new_project_page](new_project_page/default_new_project_page.png)
+
+To customize the information in the sidebar:
+
+1. Navigate to the **Admin** area and go to the **Appearance** page, then
+ locate the **New project pages** section.
+1. Fill in your new project project guidelines:
+
+ ![appearance_settings](new_project_page/appearance_settings.png)
-## Changing the appearance of the new project page
+1. Save the page.
-Navigate to the **Admin** area and go to the **Appearance** page.
+Your new project page will show the customized guidelines in the sidebar, below
+the general information:
-Fill in your project guidelines:
+![custom_new_project_page](new_project_page/custom_new_project_page.png)
-![](new_project_page/appearance_settings.png)
+<!-- ## Troubleshooting
-After saving the page, your new project page will show the guidelines in the sidebar, below the general information:
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
-![](new_project_page/custom_new_project_page.png)
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/development/README.md b/doc/development/README.md
index 99c88146be5..44283a3ab0c 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -150,6 +150,10 @@ description: 'Learn how to contribute to GitLab.'
- [Go Guidelines](go_guide/index.md)
+## Shell Scripting guides
+
+- [Shell scripting standards and style guidelines](shell_scripting_guide/index.md)
+
## Other GitLab Development Kit (GDK) guides
- [Run full Auto DevOps cycle in a GDK instance](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/auto_devops.md)
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 39f12e6886e..a38794c49af 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -240,7 +240,7 @@ know how difficult the issue is. Additionally:
as suitable for people that have never contributed to GitLab before on the
[Up For Grabs campaign](http://up-for-grabs.net)
- We encourage people that have never contributed to any open source project to
- look for [`Accepting merge requests` issues with a weight of 1][firt-timers]
+ look for [`Accepting merge requests` issues with a weight of 1][first-timers]
If you've decided that you would like to work on an issue, please @-mention
the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
@@ -253,8 +253,8 @@ GitLab team members who apply the ~"Accepting merge requests" label to an issue
should update the issue description with a responsible product manager, inviting
any potential community contributor to @-mention per above.
-[up-for-grabs]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=0&sort=weight
-[firt-timers]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=0&sort=weight&weight=1
+[up-for-grabs]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight
+[first-timers]: https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None&sort=weight&weight=1
## Issue triaging
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index ed5b23a122f..cfabc09646d 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -146,8 +146,8 @@ CREATE EXTENSION postgres_fdw;
## Unicorn Workers
-For most instances we recommend using: CPU cores + 1 = unicorn workers.
-So for a machine with 2 cores, 3 unicorn workers is ideal.
+For most instances we recommend using: (CPU cores * 1.5) + 1 = unicorn workers.
+For example a node with 4 cores would have 7 unicorn workers.
For all machines that have 2GB and up we recommend a minimum of three unicorn workers.
If you have a 1GB machine we recommend to configure only two Unicorn workers to prevent excessive swapping.
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index 626bd259ed6..1c80fc543af 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -24,18 +24,21 @@ special searches:
## Installing Elasticsearch
Elasticsearch is _not_ included in the Omnibus packages. You will have to
-install it yourself whether you are using the Omnibus package or installed
-GitLab from source. Providing detailed information on installing Elasticsearch
-is out of the scope of this document.
+[install it yourself](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html "Elasticsearch installation documentation")
+whether you are using the Omnibus package or installed GitLab from source.
+Providing detailed information on installing Elasticsearch is out of the scope
+of this document.
+
+NOTE: **Note:**
+Elasticsearch should be installed on a separate server, whether you install
+it yourself or by using the
+[Amazon Elasticsearch](http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html)
+service. Running Elasticsearch on the same server as GitLab is not recommended
+and it will likely cause performance degradation on the GitLab installation.
Once the data is added to the database or repository and [Elasticsearch is
enabled in the admin area](#enabling-elasticsearch) the search index will be
-updated automatically. Elasticsearch can be installed on the same machine as
-GitLab or on a separate server, or you can use the [Amazon Elasticsearch](http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html)
-service.
-
-You can follow the steps as described in the [official web site](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html "Elasticsearch installation documentation") or
-use the packages that are available for your OS.
+updated automatically.
## Elasticsearch repository indexer (beta)
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 0d86df04367..f8da09e5fe1 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -960,3 +960,22 @@ want to run the chown against your custom location instead of
[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
[restart GitLab]: ../administration/restart_gitlab.md#installations-from-source
+
+### Backup fails to complete with Gzip error
+
+While running the backup, you may receive a gzip error:
+
+```sh
+sudo /opt/gitlab/bin/gitlab-rake gitlab:backup:create
+Dumping ...
+...
+gzip: stdout: Input/output error
+
+Backup failed
+```
+
+If this happens, check the following:
+
+1. Confirm there is sufficent diskspace for the gzip operation.
+1. If NFS is being used, check if the mount option `timeo` is set. The default is `600`, and changing this to smaller values have resulted in this error.
+
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index 5b227ebebe0..6a539b526f3 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -72,6 +72,7 @@ The following are advanced topics for those who want to get the most out of Git:
- [Custom Git Hooks](../../administration/custom_hooks.md)
- [Git Attributes](../../user/project/git_attributes.md)
- Git Submodules: [Using Git submodules with GitLab CI](../../ci/git_submodules.md#using-git-submodules-with-gitlab-ci)
+- [Partial Clone](partial_clone.md)
## API
diff --git a/doc/topics/git/partial_clone.md b/doc/topics/git/partial_clone.md
new file mode 100644
index 00000000000..f2951308ba1
--- /dev/null
+++ b/doc/topics/git/partial_clone.md
@@ -0,0 +1,147 @@
+# Partial Clone for Large Repositories
+
+CAUTION: **Alpha:**
+Partial Clone is an experimental feature, and will significantly increase
+Gitaly resource utilization when performing a partial clone, and decrease
+performance of subsequent fetch operations.
+
+As Git repositories become very large, usability decreases as performance
+decreases. One major challenge is cloning the repository, because Git will
+download the entire repository including every commit and every version of
+every object. This can be slow to transfer, and require large amounts of disk
+space.
+
+Historically, performing a **shallow clone**
+([`--depth`](https://www.git-scm.com/docs/git-clone#Documentation/git-clone.txt---depthltdepthgt))
+has been the only way to reduce the amount of data transferred when cloning
+a Git repository. This does not, however, allow filtering by sub-tree which is
+important for monolithic repositories containing many projects, or by object
+size preventing unnecessary large objects being downloaded.
+
+[Partial clone](https://github.com/git/git/blob/master/Documentation/technical/partial-clone.txt)
+is a performance optimization that "allows Git to function without having a
+complete copy of the repository. The goal of this work is to allow Git better
+handle extremely large repositories."
+
+Specifically, using partial clone, it should be possible for Git to natively
+support:
+
+- large objects, instead of using [Git LFS](https://git-lfs.github.com/)
+- enormous repositories
+
+Briefly, partial clone works by:
+
+- excluding objects from being transferred when cloning or fetching a
+ repository using a new `--filter` flag
+- downloading missing objects on demand
+
+Follow [Git for enormous repositories](https://gitlab.com/groups/gitlab-org/-/epics/773) for roadmap and updates.
+
+## Enabling partial clone
+
+GitLab 12.1 uses Git 2.21.0 which has an arbitrary file access security
+vulnerability when `uploadpack.allowFilter` is enabled, and should not be
+enabled in production environments.
+
+A feature flag is planned to enable `uploadpack.allowFilter` and
+`uploadpack.allowAnySHA1InWant` once the version of Git used by GitLab has been
+updated to Git 2.22.0.
+
+Follow [this issue](https://gitlab.com/gitlab-org/gitaly/issues/1553) for
+updated.
+
+## Excluding objects by size
+
+Partial Clone allows large objects to be stored directly in the Git repository,
+and be excluded from clones as desired by the user. This eliminates the error
+prone process of deciding which objects should be stored in LFS or not. Using
+partial clone, all files – large or small – may be treated the same.
+
+With the `uploadpack.allowFilter` and `uploadpack.allowAnySHA1InWant` options
+enabled on the Git server:
+
+```bash
+# clone the repo, excluding blobs larger than 1 megabyte
+git clone --filter=blob:limit=1m <url>
+
+# in the checkout step of the clone, and any subsequent operations
+# any blobs that are needed will be downloaded on demand
+git checkout feature-branch
+```
+
+## Excluding objects by path
+
+Partial Clone allows clones to be filtered by path using a format similar to a
+`.gitignore` file stored inside the repository.
+
+With the `uploadpack.allowFilter` and `uploadpack.allowAnySHA1InWant` options
+enabled on the Git server:
+
+1. **Create a filter spec.** For example, consider a monolithic repository with
+ many applications, each in a different subdirectory in the root. Create a file
+ `shiny-app/.filterspec` using the GitLab web interface:
+
+ ```.gitignore
+ # Only the paths listed in the file will be downloaded when performing a
+ # partial clone using `--filter=sparse:oid=shiny-app/.gitfilterspec`
+
+ # Explicitly include filterspec needed to configure sparse checkout with
+ # git config --local core.sparsecheckout true
+ # git show master:snazzy-app/.gitfilterspec >> .git/info/sparse-checkout
+ shiny-app/.gitfilterspec
+
+ # Shiny App
+ shiny-app/
+
+ # Dependencies
+ shimmery-app/
+ shared-component-a/
+ shared-component-b/
+ ```
+
+2. *Create a new Git repository and fetch.* Support for `--filter=sparse:oid`
+ using the clone command is incomplete, so we will emulate the clone command
+ by hand, using `git init` and `git fetch`. Follow
+ [gitaly#1769](https://gitlab.com/gitlab-org/gitaly/issues/1769) for updates.
+
+ ```bash
+ # Create a new directory for the Git repository
+ mkdir jumbo-repo && cd jumbo-repo
+
+ # Initialize a new Git repository
+ git init
+
+ # Add the remote
+ git remote add origin git@gitlab.com/example/jumbo-repo
+
+ # Enable partial clone support for the remote
+ git config --local extensions.partialClone origin
+
+ # Fetch the filtered set of objects using the filterspec stored on the
+ # server. WARNING: this step is slow!
+ git fetch --filter=sparse:oid=master:shiny-app/.gitfilterspec origin
+
+ # Optional: observe there are missing objects that we have not fetched
+ git rev-list --all --quiet --objects --missing=print | wc -l
+ ```
+
+ CAUTION: **IDE and Shell integrations:**
+ Git integrations with `bash`, `zsh`, etc and editors that automatically
+ show Git status information often run `git fetch` which will fetch the
+ entire repository. You many need to disable or reconfigure these
+ integrations.
+
+3. **Sparse checkout** must be enabled and configured to prevent objects from
+ other paths being downloaded automatically when checking out branches. Follow
+ [gitaly#1765](https://gitlab.com/gitlab-org/gitaly/issues/1765) for updates.
+
+ ```bash
+ # Enable sparse checkout
+ git config --local core.sparsecheckout true
+
+ # Configure sparse checkout
+ git show master:snazzy-app/.gitfilterspec >> .git/info/sparse-checkout
+
+ # Checkout master
+ git checkout master
+ ```
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index e56acac527f..e05b3395535 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -98,7 +98,10 @@ a group in the **Usage Quotas** page available to the group page settings list.
If you're using GitLab.com, you can purchase additional CI minutes so your
pipelines will not be blocked after you have used all your CI minutes from your
-main quota.
+main quota. Additional minutes:
+
+- Are only used once the shared quota included in your subscription runs out.
+- Roll over month to month.
In order to purchase additional minutes, you should follow these steps:
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index a29df76f4b7..096730f800c 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -1,11 +1,13 @@
# GitLab Managed Apps
GitLab provides **GitLab Managed Apps**, a one-click install for various applications which can
-be added directly to your configured cluster. These applications are
-needed for [Review Apps](../../ci/review_apps/index.md) and
-[deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md).
+be added directly to your configured cluster.
+
+These applications are needed for [Review Apps](../../ci/review_apps/index.md)
+and [deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md).
+
You can install them after you
-[create a cluster](../project/clusters/index.md#add-new-gke-cluster).
+[create a cluster](../project/clusters/index.md#adding-and-removing-clusters).
## Installing applications
@@ -20,8 +22,10 @@ This namespace:
To see a list of available applications to install:
1. For a:
- - Project-level cluster, navigate to your project's **Operations > Kubernetes**.
- - Group-level cluster, navigate to your group's **Kubernetes** page.
+ - [Project-level cluster](../project/clusters/index.md),
+ navigate to your project's **Operations > Kubernetes**.
+ - [Group-level cluster](../group/clusters/index.md),
+ navigate to your group's **Kubernetes** page.
Install Helm first as it's used to install other applications.
@@ -160,9 +164,9 @@ file.
When installing JupyterHub onto your Kubernetes cluster, [JupyterLab's Git extension](https://github.com/jupyterlab/jupyterlab-git)
is automatically provisioned and configured using the authenticated user's:
-- Name
-- Email
-- Newly created access token
+- Name.
+- Email.
+- Newly created access token.
JupyterLab's Git extension enables full version control of your notebooks as well as issuance of Git commands within Jupyter.
Git commands can be issued via the **Git** tab on the left panel or via Jupyter's command line prompt.
@@ -233,8 +237,10 @@ The applications below can be upgraded.
To upgrade an application:
1. For a:
- - Project-level cluster, navigate to your project's **Operations > Kubernetes**.
- - Group-level cluster, navigate to your group's **Kubernetes** page.
+ - [Project-level cluster](../project/clusters/index.md),
+ navigate to your project's **Operations > Kubernetes**.
+ - [Group-level cluster](../group/clusters/index.md),
+ navigate to your group's **Kubernetes** page.
1. Select your cluster.
1. If an upgrade is available, the **Upgrade** button is displayed. Click the button to upgrade.
@@ -252,6 +258,7 @@ The applications below can be uninstalled.
| Application | GitLab version | Notes |
| ----------- | -------------- | ----- |
+| Cert-Manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html) or [revoke your certificates](https://letsencrypt.org/docs/revoking/) |
| GitLab Runner | 12.2+ | Any running pipelines will be canceled. |
| Helm | 12.2+ | The associated Tiller pod will be deleted and cannot be restored. |
| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
@@ -262,8 +269,10 @@ The applications below can be uninstalled.
To uninstall an application:
1. For a:
- - Project-level cluster, navigate to your project's **Operations > Kubernetes**.
- - Group-level cluster, navigate to your group's **Kubernetes** page.
+ - [Project-level cluster](../project/clusters/index.md),
+ navigate to your project's **Operations > Kubernetes**.
+ - [Group-level cluster](../group/clusters/index.md),
+ navigate to your group's **Kubernetes** page.
1. Select your cluster.
1. Click the **Uninstall** button for the application.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index e6822f0c52c..d92435ef724 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -64,7 +64,6 @@ The following table depicts the various user permission levels in a project.
| Lock issue threads | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
| Manage related issues **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
-| Create issue from vulnerability **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
@@ -94,6 +93,8 @@ The following table depicts the various user permission levels in a project.
| Remove a container registry image | | | ✓ | ✓ | ✓ |
| Create/edit/delete project milestones | | | ✓ | ✓ | ✓ |
| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| View dependency list **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| Create issue from vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ |
@@ -211,7 +212,8 @@ group.
| Create project in group | | | ✓ | ✓ | ✓ |
| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
-| Create subgroup | | | | ✓ (1) | ✓ |
+| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| Create subgroup | | | | ✓ (1) | ✓ |
| Edit group | | | | | ✓ |
| Manage group members | | | | | ✓ |
| Remove group | | | | | ✓ |
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index e609fe43507..44439b59e77 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -98,7 +98,10 @@ You can view the performance dashboard for an environment by [clicking on the mo
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3799) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.6.
-Additional metrics can be monitored by adding them on the Prometheus integration page. Once saved, they will be displayed on the environment performance dashboard.
+Custom metrics can be monitored by adding them on the Prometheus integration page. Once saved, they will be displayed on the environment performance dashboard provided that either:
+
+- A [connected Kubernetes cluster](../clusters/index.md#adding-and-removing-clusters) with the environment scope of `*` is used and [Prometheus installed on the cluster](#enabling-prometheus-integration), or
+- Prometheus is [manually configured](#manual-configuration-of-prometheus).
![Add New Metric](img/prometheus_add_metric.png)
diff --git a/doc/user/project/pipelines/settings.md b/doc/user/project/pipelines/settings.md
index 45f27b3c811..456209c2180 100644
--- a/doc/user/project/pipelines/settings.md
+++ b/doc/user/project/pipelines/settings.md
@@ -76,6 +76,13 @@ Here are some valid examples:
- `my/path/.gitlab-ci.yml`
- `my/path/.my-custom-file.yml`
+The path can be customized at a project level. To customize the path:
+
+1. Go to the project's **Settings > CI / CD**.
+1. Expand the **General pipelines** section.
+1. Provide a value in the **Custom CI config path** field.
+1. Click **Save changes**.
+
## Test coverage parsing
If you use test coverage in your code, GitLab can capture its output in the
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index b8e0ef8d12f..437899dce1e 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -70,6 +70,19 @@ Many quick actions require a parameter, for example: username, milestone, and
label. [Autocomplete characters](autocomplete_characters.md) can make it easier
to enter a parameter, compared to selecting items from a list.
+## Quick actions parameters
+
+The easiest way to set parameters for quick actions is to use autocomplete. If
+you manually enter a parameter, it must be enclosed in double quotation marks
+(`"`), unless it contains only:
+
+1. ASCII letters.
+2. Numerals.
+3. Underscore, hyphen, question mark, dot, and ampersand.
+
+Parameters are also case-sensitive. Autocomplete handles this, and the insertion
+of quotation marks, automatically.
+
## Quick actions for commit messages
The following quick actions are applicable for commit messages:
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 223ae13bd2d..e500a93b31e 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -104,7 +104,6 @@ module API
mount ::API::BroadcastMessages
mount ::API::Commits
mount ::API::CommitStatuses
- mount ::API::ContainerRegistry
mount ::API::DeployKeys
mount ::API::Deployments
mount ::API::Environments
@@ -116,6 +115,7 @@ module API
mount ::API::GroupLabels
mount ::API::GroupMilestones
mount ::API::Groups
+ mount ::API::GroupContainerRepositories
mount ::API::GroupVariables
mount ::API::ImportGithub
mount ::API::Internal
@@ -138,6 +138,7 @@ module API
mount ::API::Pipelines
mount ::API::PipelineSchedules
mount ::API::ProjectClusters
+ mount ::API::ProjectContainerRepositories
mount ::API::ProjectEvents
mount ::API::ProjectExport
mount ::API::ProjectImport
diff --git a/lib/api/entities/container_registry.rb b/lib/api/entities/container_registry.rb
index 00833ca7480..6250f35c7cb 100644
--- a/lib/api/entities/container_registry.rb
+++ b/lib/api/entities/container_registry.rb
@@ -3,18 +3,20 @@
module API
module Entities
module ContainerRegistry
- class Repository < Grape::Entity
- expose :id
+ class Tag < Grape::Entity
expose :name
expose :path
expose :location
- expose :created_at
end
- class Tag < Grape::Entity
+ class Repository < Grape::Entity
+ expose :id
expose :name
expose :path
+ expose :project_id
expose :location
+ expose :created_at
+ expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
end
class TagDetails < Tag
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
new file mode 100644
index 00000000000..fd24662cc9a
--- /dev/null
+++ b/lib/api/group_container_repositories.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module API
+ class GroupContainerRepositories < Grape::API
+ include PaginationParams
+
+ before { authorize_read_group_container_images! }
+
+ REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ tag_name: API::NO_SLASH_URL_PART_REGEX)
+
+ params do
+ requires :id, type: String, desc: "Group's ID or path"
+ end
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get a list of all repositories within a group' do
+ detail 'This feature was introduced in GitLab 12.2.'
+ success Entities::ContainerRegistry::Repository
+ end
+ params do
+ use :pagination
+ optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
+ end
+ get ':id/registry/repositories' do
+ repositories = ContainerRepositoriesFinder.new(
+ id: user_group.id, container_type: :group
+ ).execute
+
+ present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
+ end
+ end
+
+ helpers do
+ def authorize_read_group_container_images!
+ authorize! :read_container_image, user_group
+ end
+ end
+ end
+end
diff --git a/lib/api/container_registry.rb b/lib/api/project_container_repositories.rb
index 7dad20a822a..6d53abcc500 100644
--- a/lib/api/container_registry.rb
+++ b/lib/api/project_container_repositories.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
module API
- class ContainerRegistry < Grape::API
+ class ProjectContainerRepositories < Grape::API
include PaginationParams
- REGISTRY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
+ REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
tag_name: API::NO_SLASH_URL_PART_REGEX)
before { error!('404 Not Found', 404) unless Feature.enabled?(:container_registry_api, user_project, default_enabled: true) }
@@ -20,11 +20,14 @@ module API
end
params do
use :pagination
+ optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
end
get ':id/registry/repositories' do
- repositories = user_project.container_repositories.ordered
+ repositories = ContainerRepositoriesFinder.new(
+ id: user_project.id, container_type: :project
+ ).execute
- present paginate(repositories), with: Entities::ContainerRegistry::Repository
+ present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags]
end
desc 'Delete repository' do
@@ -33,7 +36,7 @@ module API
params do
requires :repository_id, type: Integer, desc: 'The ID of the repository'
end
- delete ':id/registry/repositories/:repository_id', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id)
@@ -49,7 +52,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
use :pagination
end
- get ':id/registry/repositories/:repository_id/tags', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ get ':id/registry/repositories/:repository_id/tags', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_read_container_image!
tags = Kaminari.paginate_array(repository.tags)
@@ -65,7 +68,7 @@ module API
optional :keep_n, type: Integer, desc: 'Keep n of latest tags with matching name'
optional :older_than, type: String, desc: 'Delete older than: 1h, 1d, 1month'
end
- delete ':id/registry/repositories/:repository_id/tags', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id/tags', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
message = 'This request has already been made. You can run this at most once an hour for a given container repository'
@@ -85,7 +88,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
requires :tag_name, type: String, desc: 'The name of the tag'
end
- get ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ get ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_read_container_image!
validate_tag!
@@ -99,7 +102,7 @@ module API
requires :repository_id, type: Integer, desc: 'The ID of the repository'
requires :tag_name, type: String, desc: 'The name of the tag'
end
- delete ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REGISTRY_ENDPOINT_REQUIREMENTS do
+ delete ':id/registry/repositories/:repository_id/tags/:tag_name', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_destroy_container_image!
validate_tag!
diff --git a/lib/gitlab/background_migration/migrate_legacy_artifacts.rb b/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
index 5cd638083b0..4377ec2987c 100644
--- a/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
+++ b/lib/gitlab/background_migration/migrate_legacy_artifacts.rb
@@ -39,10 +39,10 @@ module Gitlab
SELECT
project_id,
id,
- artifacts_expire_at,
+ artifacts_expire_at #{add_missing_db_timezone},
#{LEGACY_PATH_FILE_LOCATION},
- created_at,
- created_at,
+ created_at #{add_missing_db_timezone},
+ created_at #{add_missing_db_timezone},
artifacts_file,
artifacts_size,
COALESCE(artifacts_file_store, #{FILE_LOCAL_STORE}),
@@ -81,10 +81,10 @@ module Gitlab
SELECT
project_id,
id,
- artifacts_expire_at,
+ artifacts_expire_at #{add_missing_db_timezone},
#{LEGACY_PATH_FILE_LOCATION},
- created_at,
- created_at,
+ created_at #{add_missing_db_timezone},
+ created_at #{add_missing_db_timezone},
artifacts_metadata,
NULL,
COALESCE(artifacts_metadata_store, #{FILE_LOCAL_STORE}),
@@ -121,6 +121,12 @@ module Gitlab
AND artifacts_file <> ''
SQL
end
+
+ def add_missing_db_timezone
+ return '' unless Gitlab::Database.postgresql?
+
+ 'at time zone \'UTC\''
+ end
end
end
end
diff --git a/lib/gitlab/cycle_analytics/base_query.rb b/lib/gitlab/cycle_analytics/base_query.rb
index 9c98c0bfbf2..459bb5177b5 100644
--- a/lib/gitlab/cycle_analytics/base_query.rb
+++ b/lib/gitlab/cycle_analytics/base_query.rb
@@ -19,9 +19,10 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
- .where(issue_table[:project_id].in(project_ids))
- .where(routes_table[:source_type].eq('Namespace'))
- .where(issue_table[:created_at].gteq(options[:from]))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
+
+ query = limit_query(query, project_ids)
# Load merge_requests
@@ -30,6 +31,12 @@ module Gitlab
query
end
+ def limit_query(query, project_ids)
+ query.where(issue_table[:project_id].in(project_ids))
+ .where(routes_table[:source_type].eq('Namespace'))
+ .where(issue_table[:created_at].gteq(options[:from]))
+ end
+
def load_merge_requests(query)
query.join(mr_table, Arel::Nodes::OuterJoin)
.on(mr_table[:id].eq(mr_closing_issues_table[:merge_request_id]))
diff --git a/lib/gitlab/cycle_analytics/code_event_fetcher.rb b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
index 1e4e9b9e02c..fcc282bf7a6 100644
--- a/lib/gitlab/cycle_analytics/code_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/code_event_fetcher.rb
@@ -11,9 +11,7 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ mr_table[:author_id]]
@order = mr_table[:created_at]
super(*args)
diff --git a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
index 2d03e425a6a..6914cf24c19 100644
--- a/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/issue_event_fetcher.rb
@@ -10,9 +10,7 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ issue_table[:author_id]]
super(*args)
end
diff --git a/lib/gitlab/cycle_analytics/issue_helper.rb b/lib/gitlab/cycle_analytics/issue_helper.rb
index 0fc4f1dd41a..295eca5edca 100644
--- a/lib/gitlab/cycle_analytics/issue_helper.rb
+++ b/lib/gitlab/cycle_analytics/issue_helper.rb
@@ -8,12 +8,19 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
- .where(issue_table[:project_id].in(project_ids))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
+
+ query = limit_query(query, project_ids)
+
+ query
+ end
+
+ def limit_query(query, project_ids)
+ query.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
-
- query
end
end
end
diff --git a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
index 77cc358daa9..bad02e00a13 100644
--- a/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/plan_event_fetcher.rb
@@ -10,9 +10,7 @@ module Gitlab
issue_table[:iid],
issue_table[:id],
issue_table[:created_at],
- issue_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ issue_table[:author_id]]
super(*args)
end
diff --git a/lib/gitlab/cycle_analytics/plan_helper.rb b/lib/gitlab/cycle_analytics/plan_helper.rb
index c3f742503a9..a63ae58ad21 100644
--- a/lib/gitlab/cycle_analytics/plan_helper.rb
+++ b/lib/gitlab/cycle_analytics/plan_helper.rb
@@ -8,14 +8,16 @@ module Gitlab
.join(projects_table).on(issue_table[:project_id].eq(projects_table[:id]))
.join(routes_table).on(projects_table[:namespace_id].eq(routes_table[:source_id]))
.project(issue_table[:project_id].as("project_id"))
+ .project(projects_table[:path].as("project_path"))
+ .project(routes_table[:path].as("namespace_path"))
.where(issue_table[:project_id].in(project_ids))
.where(routes_table[:source_type].eq('Namespace'))
- query = add_conditions_to_query(query)
+ query = limit_query(query)
query
end
- def add_conditions_to_query(query)
+ def limit_query(query)
query.where(issue_table[:created_at].gteq(options[:from]))
.where(issue_metrics_table[:first_added_to_board_at].not_eq(nil).or(issue_metrics_table[:first_associated_with_milestone_at].not_eq(nil)))
.where(issue_metrics_table[:first_mentioned_in_commit_at].not_eq(nil))
diff --git a/lib/gitlab/cycle_analytics/production_event_fetcher.rb b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
index 404b2460814..8843ab2bcb9 100644
--- a/lib/gitlab/cycle_analytics/production_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/production_event_fetcher.rb
@@ -11,7 +11,6 @@ module Gitlab
issue_table[:id],
issue_table[:created_at],
issue_table[:author_id],
- projects_table[:name],
routes_table[:path]]
super(*args)
diff --git a/lib/gitlab/cycle_analytics/review_event_fetcher.rb b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
index 6acd12517fa..4b5d79097b7 100644
--- a/lib/gitlab/cycle_analytics/review_event_fetcher.rb
+++ b/lib/gitlab/cycle_analytics/review_event_fetcher.rb
@@ -11,9 +11,7 @@ module Gitlab
mr_table[:id],
mr_table[:created_at],
mr_table[:state],
- mr_table[:author_id],
- projects_table[:name],
- routes_table[:path]]
+ mr_table[:author_id]]
super(*args)
end
diff --git a/lib/peek/views/redis_detailed.rb b/lib/peek/views/redis_detailed.rb
index b95307deddb..f36f581d5e9 100644
--- a/lib/peek/views/redis_detailed.rb
+++ b/lib/peek/views/redis_detailed.rb
@@ -16,6 +16,7 @@ module Gitlab
private
def add_call_details(duration, args)
+ return unless peek_enabled?
# redis-rb passes an array (e.g. [:get, key])
return unless args.length == 1
@@ -26,6 +27,10 @@ module Gitlab
}
end
+ def peek_enabled?
+ Gitlab::SafeRequestStore.store[:peek_enabled]
+ end
+
def detail_store
::Gitlab::SafeRequestStore['redis_call_details'] ||= []
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d462bb03adf..86317dd887f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -900,6 +900,9 @@ msgstr ""
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
msgstr ""
+msgid "Alerts"
+msgstr ""
+
msgid "All"
msgstr ""
@@ -2827,10 +2830,10 @@ msgstr ""
msgid "ClusterIntegration|The associated Tiller pod will be deleted and cannot be restored."
msgstr ""
-msgid "ClusterIntegration|The associated certifcate will be deleted and cannot be restored."
+msgid "ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored."
msgstr ""
-msgid "ClusterIntegration|The associated load balancer and IP will be deleted and cannot be restored."
+msgid "ClusterIntegration|The associated private key will be deleted and cannot be restored."
msgstr ""
msgid "ClusterIntegration|The endpoint is in the process of being assigned. Please check your Kubernetes cluster or Quotas on Google Kubernetes Engine if it takes a long time."
@@ -6868,6 +6871,9 @@ msgstr ""
msgid "More"
msgstr ""
+msgid "More actions"
+msgstr ""
+
msgid "More information"
msgstr ""
diff --git a/package.json b/package.json
index bf6000dc53d..4ff99f29e24 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
"@gitlab/svgs": "^1.67.0",
- "@gitlab/ui": "5.12.1",
+ "@gitlab/ui": "5.14.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb
index 24c22ef3928..89f7bc15217 100644
--- a/spec/factories/clusters/applications/helm.rb
+++ b/spec/factories/clusters/applications/helm.rb
@@ -4,6 +4,20 @@ FactoryBot.define do
factory :clusters_applications_helm, class: Clusters::Applications::Helm do
cluster factory: %i(cluster provided_by_gcp)
+ before(:create) do
+ allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root)
+ .and_return(
+ double(
+ key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')),
+ cert_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_cert.pem'))
+ )
+ )
+ end
+
+ after(:create) do
+ allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root).and_call_original
+ end
+
trait :not_installable do
status(-2)
end
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index 8cfd23d16df..3d15095e2da 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -183,7 +183,7 @@ describe 'Clusters Applications', :js do
Clusters::Cluster.last.application_cert_manager.make_installed!
expect(email_form_value).to eq('new_email@example.org')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed')
+ expect(page).to have_css('.js-cluster-application-uninstall-button', exact_text: 'Uninstall')
end
expect(page).to have_content('Cert-Manager was successfully installed on your Kubernetes cluster')
diff --git a/spec/finders/container_repositories_finder_spec.rb b/spec/finders/container_repositories_finder_spec.rb
new file mode 100644
index 00000000000..deec62d6598
--- /dev/null
+++ b/spec/finders/container_repositories_finder_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ContainerRepositoriesFinder do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+ let(:project_repository) { create(:container_repository, project: project) }
+
+ describe '#execute' do
+ let(:id) { nil }
+
+ subject { described_class.new(id: id, container_type: container_type).execute }
+
+ context 'when container_type is group' do
+ let(:other_project) { create(:project, group: group) }
+
+ let(:other_repository) do
+ create(:container_repository, name: 'test_repository2', project: other_project)
+ end
+
+ let(:container_type) { :group }
+ let(:id) { group.id }
+
+ it { is_expected.to match_array([project_repository, other_repository]) }
+ end
+
+ context 'when container_type is project' do
+ let(:container_type) { :project }
+ let(:id) { project.id }
+
+ it { is_expected.to match_array([project_repository]) }
+ end
+
+ context 'with invalid id' do
+ let(:container_type) { :project }
+ let(:id) { 123456789 }
+
+ it 'raises an error' do
+ expect { subject.execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+end
diff --git a/spec/fixtures/api/schemas/registry/repository.json b/spec/fixtures/api/schemas/registry/repository.json
index e0fd4620c43..d0a068b65a7 100644
--- a/spec/fixtures/api/schemas/registry/repository.json
+++ b/spec/fixtures/api/schemas/registry/repository.json
@@ -17,6 +17,9 @@
"path": {
"type": "string"
},
+ "project_id": {
+ "type": "integer"
+ },
"location": {
"type": "string"
},
@@ -28,7 +31,8 @@
},
"destroy_path": {
"type": "string"
- }
+ },
+ "tags": { "$ref": "tags.json" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/clusters/sample_key.key b/spec/fixtures/clusters/sample_key.key
new file mode 100644
index 00000000000..4ddb20b0922
--- /dev/null
+++ b/spec/fixtures/clusters/sample_key.key
@@ -0,0 +1,9 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIBOgIBAAJBAMA5sXIBE0HwgIB40iNidN4PGWzOyLQK0bsdOBNgpEXkDlZBvnak
+OUgAPF+rME4PB0Yl415DabUI40T5UNmlwxcCAwEAAQJAZtY2pSwIFm3JAXIh0cZZ
+iXcAfiJ+YzuqinUOS+eW2sBCAEzjcARlU/o6sFQgtsOi4FOMczAd1Yx8UDMXMmrw
+2QIhAPBgVhJiTF09pdmeFWutCvTJDlFFAQNbrbo2X2x/9WF9AiEAzLgqMKeStSRu
+H9N16TuDrUoO8R+DPqriCwkKrSHaWyMCIFzMhE4inuKcSywBaLmiG4m3GQzs++Al
+A6PRG/PSTpQtAiBxtBg6zdf+JC3GH3zt/dA0/10tL4OF2wORfYQghRzyYQIhAL2l
+0ZQW+yLIZAGrdBFWYEAa52GZosncmzBNlsoTgwE4
+-----END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/spec/javascripts/jobs/components/job_app_spec.js b/spec/javascripts/jobs/components/job_app_spec.js
index b53890f8348..d3c1cf831bb 100644
--- a/spec/javascripts/jobs/components/job_app_spec.js
+++ b/spec/javascripts/jobs/components/job_app_spec.js
@@ -24,6 +24,7 @@ describe('Job App ', () => {
variablesSettingsUrl: 'settings/ci-cd/variables',
terminalPath: 'jobs/123/terminal',
pagePath: `${gl.TEST_HOST}jobs/123`,
+ projectPath: 'user-name/project-name',
logState:
'eyJvZmZzZXQiOjE3NDUxLCJuX29wZW5fdGFncyI6MCwiZmdfY29sb3IiOm51bGwsImJnX2NvbG9yIjpudWxsLCJzdHlsZV9tYXNrIjowfQ%3D%3D',
};
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index e956a2355db..93050e80b07 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -13,7 +13,7 @@ describe Clusters::Applications::CertManager do
describe '#can_uninstall?' do
subject { cert_manager.can_uninstall? }
- it { is_expected.to be_falsey }
+ it { is_expected.to be_truthy }
end
describe '#install_command' do
@@ -80,6 +80,44 @@ describe Clusters::Applications::CertManager do
end
end
+ describe '#uninstall_command' do
+ subject { cert_manager.uninstall_command }
+
+ it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) }
+
+ it 'is initialized with cert_manager arguments' do
+ expect(subject.name).to eq('certmanager')
+ expect(subject).to be_rbac
+ expect(subject.files).to eq(cert_manager.files)
+ end
+
+ it 'specifies a post delete command to remove custom resource definitions' do
+ expect(subject.postdelete).to eq([
+ "kubectl delete secret -n gitlab-managed-apps letsencrypt-prod --ignore-not-found",
+ 'kubectl delete crd certificates.certmanager.k8s.io --ignore-not-found',
+ 'kubectl delete crd clusterissuers.certmanager.k8s.io --ignore-not-found',
+ 'kubectl delete crd issuers.certmanager.k8s.io --ignore-not-found'
+ ])
+ end
+
+ context 'secret key name is not found' do
+ before do
+ allow(File).to receive(:read).and_call_original
+ expect(File).to receive(:read)
+ .with(Rails.root.join('vendor', 'cert_manager', 'cluster_issuer.yaml'))
+ .and_return('key: value')
+ end
+
+ it 'does not try and delete the secret' do
+ expect(subject.postdelete).to eq([
+ 'kubectl delete crd certificates.certmanager.k8s.io --ignore-not-found',
+ 'kubectl delete crd clusterissuers.certmanager.k8s.io --ignore-not-found',
+ 'kubectl delete crd issuers.certmanager.k8s.io --ignore-not-found'
+ ])
+ end
+ end
+ end
+
describe '#files' do
let(:application) { cert_manager }
let(:values) { subject[:'values.yaml'] }
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 7e9bbf5a407..1c41ceb7deb 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -23,6 +23,7 @@ describe Group do
it { is_expected.to have_many(:badges).class_name('GroupBadge') }
it { is_expected.to have_many(:cluster_groups).class_name('Clusters::Group') }
it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') }
+ it { is_expected.to have_many(:container_repositories) }
describe '#members & #requesters' do
let(:requester) { create(:user) }
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
new file mode 100644
index 00000000000..0a41e455d01
--- /dev/null
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::GroupContainerRepositories do
+ set(:group) { create(:group, :private) }
+ set(:project) { create(:project, :private, group: group) }
+ let(:reporter) { create(:user) }
+ let(:guest) { create(:user) }
+
+ let(:root_repository) { create(:container_repository, :root, project: project) }
+ let(:test_repository) { create(:container_repository, project: project) }
+
+ let(:users) do
+ {
+ anonymous: nil,
+ guest: guest,
+ reporter: reporter
+ }
+ end
+
+ let(:api_user) { reporter }
+
+ before do
+ group.add_reporter(reporter)
+ group.add_guest(guest)
+
+ stub_feature_flags(container_registry_api: true)
+ stub_container_registry_config(enabled: true)
+
+ root_repository
+ test_repository
+ end
+
+ describe 'GET /groups/:id/registry/repositories' do
+ let(:url) { "/groups/#{group.id}/registry/repositories" }
+
+ subject { get api(url, api_user) }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+
+ it_behaves_like 'returns repositories for allowed users', :reporter, 'group' do
+ let(:object) { group }
+ end
+
+ context 'with invalid group id' do
+ let(:url) { '/groups/123412341234/registry/repositories' }
+
+ it 'returns not found' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/container_registry_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index b64f3ea1081..f1dc4e6f0b2 100644
--- a/spec/requests/api/container_registry_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::ContainerRegistry do
+describe API::ProjectContainerRepositories do
include ExclusiveLeaseHelpers
set(:project) { create(:project, :private) }
@@ -12,6 +12,16 @@ describe API::ContainerRegistry do
let(:root_repository) { create(:container_repository, :root, project: project) }
let(:test_repository) { create(:container_repository, project: project) }
+ let(:users) do
+ {
+ anonymous: nil,
+ developer: developer,
+ guest: guest,
+ maintainer: maintainer,
+ reporter: reporter
+ }
+ end
+
let(:api_user) { maintainer }
before do
@@ -27,57 +37,24 @@ describe API::ContainerRegistry do
test_repository
end
- shared_examples 'being disallowed' do |param|
- context "for #{param}" do
- let(:api_user) { public_send(param) }
-
- it 'returns access denied' do
- subject
-
- expect(response).to have_gitlab_http_status(:forbidden)
- end
- end
-
- context "for anonymous" do
- let(:api_user) { nil }
-
- it 'returns not found' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
describe 'GET /projects/:id/registry/repositories' do
- subject { get api("/projects/#{project.id}/registry/repositories", api_user) }
-
- it_behaves_like 'being disallowed', :guest
-
- context 'for reporter' do
- let(:api_user) { reporter }
-
- it 'returns a list of repositories' do
- subject
+ let(:url) { "/projects/#{project.id}/registry/repositories" }
- expect(json_response.length).to eq(2)
- expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
- root_repository.id, test_repository.id)
- end
+ subject { get api(url, api_user) }
- it 'returns a matching schema' do
- subject
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('registry/repositories')
- end
+ it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
+ let(:object) { project }
end
end
describe 'DELETE /projects/:id/registry/repositories/:repository_id' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}", api_user) }
- it_behaves_like 'being disallowed', :developer
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for maintainer' do
let(:api_user) { maintainer }
@@ -96,7 +73,8 @@ describe API::ContainerRegistry do
describe 'GET /projects/:id/registry/repositories/:repository_id/tags' do
subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user) }
- it_behaves_like 'being disallowed', :guest
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for reporter' do
let(:api_user) { reporter }
@@ -124,10 +102,13 @@ describe API::ContainerRegistry do
describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags", api_user), params: params }
- it_behaves_like 'being disallowed', :developer do
+ context 'disallowed' do
let(:params) do
{ name_regex: 'v10.*' }
end
+
+ it_behaves_like 'rejected container repository access', :developer, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
end
context 'for maintainer' do
@@ -191,7 +172,8 @@ describe API::ContainerRegistry do
describe 'GET /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
subject { get api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
- it_behaves_like 'being disallowed', :guest
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for reporter' do
let(:api_user) { reporter }
@@ -222,7 +204,8 @@ describe API::ContainerRegistry do
describe 'DELETE /projects/:id/registry/repositories/:repository_id/tags/:tag_name' do
subject { delete api("/projects/#{project.id}/registry/repositories/#{root_repository.id}/tags/rootA", api_user) }
- it_behaves_like 'being disallowed', :reporter
+ it_behaves_like 'rejected container repository access', :reporter, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
context 'for developer' do
let(:api_user) { developer }
diff --git a/spec/serializers/analytics_issue_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb
index dd5e43a4b62..c5b03bdd8c1 100644
--- a/spec/serializers/analytics_issue_entity_spec.rb
+++ b/spec/serializers/analytics_issue_entity_spec.rb
@@ -10,12 +10,12 @@ describe AnalyticsIssueEntity do
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:request) { EntityRequest.new(entity: :merge_request) }
let(:entity) do
diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb
index c9ffe1c5dad..9cb2ce13d12 100644
--- a/spec/serializers/analytics_issue_serializer_spec.rb
+++ b/spec/serializers/analytics_issue_serializer_spec.rb
@@ -8,7 +8,7 @@ describe AnalyticsIssueSerializer do
end
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:resource) do
{
total_time: "172802.724419",
@@ -17,8 +17,8 @@ describe AnalyticsIssueSerializer do
id: "1",
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb
index 123d7d795ce..a864051b2a3 100644
--- a/spec/serializers/analytics_merge_request_serializer_spec.rb
+++ b/spec/serializers/analytics_merge_request_serializer_spec.rb
@@ -8,7 +8,7 @@ describe AnalyticsMergeRequestSerializer do
end
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'my project') }
let(:resource) do
{
total_time: "172802.724419",
@@ -18,8 +18,8 @@ describe AnalyticsMergeRequestSerializer do
state: 'open',
created_at: "2016-11-12 15:04:02.948604",
author: user,
- name: project.name,
- path: project.namespace
+ project_path: project.path,
+ namespace_path: project.namespace.route.path
}
end
diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
index c11725c63d2..fd24c443288 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -16,7 +16,7 @@ RSpec.shared_context 'GroupPolicy context' do
read_group_merge_requests
]
end
- let(:reporter_permissions) { [:admin_label] }
+ let(:reporter_permissions) { %i[admin_label read_container_image] }
let(:developer_permissions) { [:admin_milestone] }
let(:maintainer_permissions) do
%i[
diff --git a/spec/support/shared_examples/container_repositories_shared_examples.rb b/spec/support/shared_examples/container_repositories_shared_examples.rb
new file mode 100644
index 00000000000..946b130fca2
--- /dev/null
+++ b/spec/support/shared_examples/container_repositories_shared_examples.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+shared_examples 'rejected container repository access' do |user_type, status|
+ context "for #{user_type}" do
+ let(:api_user) { users[user_type] }
+
+ it "returns #{status}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+end
+
+shared_examples 'returns repositories for allowed users' do |user_type, scope|
+ context "for #{user_type}" do
+ it 'returns a list of repositories' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).not_to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+
+ context 'with tags param' do
+ let(:url) { "/#{scope}s/#{object.id}/registry/repositories?tags=true" }
+
+ before do
+ stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest), with_manifest: true)
+ stub_container_registry_tags(repository: test_repository.path, tags: %w(rootA latest), with_manifest: true)
+ end
+
+ it 'returns a list of repositories and their tags' do
+ subject
+
+ expect(json_response.length).to eq(2)
+ expect(json_response.map { |repository| repository['id'] }).to contain_exactly(
+ root_repository.id, test_repository.id)
+ expect(response.body).to include('tags')
+ end
+
+ it 'returns a matching schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('registry/repositories')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/relative_positioning_shared_examples.rb b/spec/support/shared_examples/relative_positioning_shared_examples.rb
index 1c53e2602eb..9837ba806db 100644
--- a/spec/support/shared_examples/relative_positioning_shared_examples.rb
+++ b/spec/support/shared_examples/relative_positioning_shared_examples.rb
@@ -9,6 +9,12 @@ RSpec.shared_examples 'a class that supports relative positioning' do
create(factory, params.merge(default_params))
end
+ def create_items_with_positions(positions)
+ positions.map do |position|
+ create_item(relative_position: position)
+ end
+ end
+
describe '.move_nulls_to_end' do
it 'moves items with null relative_position to the end' do
skip("#{item1} has a default relative position") if item1.relative_position
@@ -104,46 +110,6 @@ RSpec.shared_examples 'a class that supports relative positioning' do
end
end
- describe '#shift_after?' do
- before do
- [item1, item2].each do |item1|
- item1.move_to_end && item1.save
- end
- end
-
- it 'returns true' do
- item1.update(relative_position: item2.relative_position - 1)
-
- expect(item1.shift_after?).to be_truthy
- end
-
- it 'returns false' do
- item1.update(relative_position: item2.relative_position - 2)
-
- expect(item1.shift_after?).to be_falsey
- end
- end
-
- describe '#shift_before?' do
- before do
- [item1, item2].each do |item1|
- item1.move_to_end && item1.save
- end
- end
-
- it 'returns true' do
- item1.update(relative_position: item2.relative_position + 1)
-
- expect(item1.shift_before?).to be_truthy
- end
-
- it 'returns false' do
- item1.update(relative_position: item2.relative_position + 2)
-
- expect(item1.shift_before?).to be_falsey
- end
- end
-
describe '#move_between' do
before do
[item1, item2].each do |item1|
@@ -257,5 +223,61 @@ RSpec.shared_examples 'a class that supports relative positioning' do
expect(new_item.relative_position).to be(100)
end
+
+ it 'avoids N+1 queries when rebalancing other items' do
+ items = create_items_with_positions([100, 101, 102])
+
+ count = ActiveRecord::QueryRecorder.new do
+ new_item.move_between(items[-2], items[-1])
+ end
+
+ items = create_items_with_positions([150, 151, 152, 153, 154])
+
+ expect { new_item.move_between(items[-2], items[-1]) }.not_to exceed_query_limit(count)
+ end
+ end
+
+ describe '#move_sequence_before' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([90, 100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([90, 95, 96, 102])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.last.move_sequence_before
+ items.last.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([50, 51, 102])
+ end
+ end
+
+ describe '#move_sequence_after' do
+ it 'moves the whole sequence of items to the middle of the nearest gap' do
+ items = create_items_with_positions([100, 101, 102, 110])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 105, 106, 110])
+ end
+
+ it 'finds a gap if there are unused positions' do
+ items = create_items_with_positions([100, 101, 102])
+
+ items.first.move_sequence_after
+ items.first.save!
+
+ positions = items.map { |item| item.reload.relative_position }
+ expect(positions).to eq([100, 601, 602])
+ end
end
end
diff --git a/yarn.lock b/yarn.lock
index d8193af1310..acf1a4d8652 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -996,10 +996,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579"
integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA==
-"@gitlab/ui@5.12.1":
- version "5.12.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.12.1.tgz#70035747cec96a729e012924ab2d3e3b6067a558"
- integrity sha512-W4rvZj2Fab1UpXR0Wyi7wSvj+5Ko+TWHibC/q/FSRHMsbeSLq77lljd7rQWeXXNMBvEKwr4NqSmckWsjaSOLfw==
+"@gitlab/ui@5.14.0":
+ version "5.14.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.14.0.tgz#850214cfc6bb57f7ce672dc1cc60ea3d39ad41f3"
+ integrity sha512-JXUmk+hT4Rj2GBh0xAF43dYeloBEDX22rgeaDU6/RzD3JEA353yEm2+HOsBjPkQFDAh6Zp7OZSBuhDFrQe8sbg==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"