summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-18 09:09:32 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-18 09:09:32 +0000
commita8b87b4fe0ebd38c0f1d7789ae768a6bcacb6c51 (patch)
treec1526cfec8ac3d9189188e08265ef1110419f643
parent0115b63f646be489bb9685dad0e4b0747a79de05 (diff)
downloadgitlab-ce-a8b87b4fe0ebd38c0f1d7789ae768a6bcacb6c51.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue37
-rw-r--r--app/assets/javascripts/releases/components/releases_pagination_graphql.vue6
-rw-r--r--app/assets/javascripts/releases/components/releases_pagination_rest.vue4
-rw-r--r--app/assets/javascripts/releases/mount_index.js5
-rw-r--r--app/assets/javascripts/releases/stores/modules/list/actions.js6
-rw-r--r--app/assets/stylesheets/pages/issuable.scss1
-rw-r--r--app/assets/stylesheets/pages/issues.scss2
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/admin/plan_limits_controller.rb39
-rw-r--r--app/views/admin/application_settings/_package_registry.html.haml50
-rw-r--r--app/views/projects/_merge_request_merge_checks_settings.html.haml2
-rw-r--r--changelogs/unreleased/240951-package-size-limits-ui.yml5
-rw-r--r--changelogs/unreleased/250279-unnecessary-spacing-exists-in-issues-list.yml5
-rw-r--r--config/routes/admin.rb2
-rw-r--r--doc/administration/reference_architectures/10k_users.md8
-rw-r--r--doc/administration/reference_architectures/25k_users.md8
-rw-r--r--doc/administration/reference_architectures/2k_users.md14
-rw-r--r--doc/administration/reference_architectures/3k_users.md8
-rw-r--r--doc/administration/reference_architectures/50k_users.md8
-rw-r--r--doc/administration/reference_architectures/5k_users.md8
-rw-r--r--doc/install/installation.md9
-rw-r--r--doc/install/requirements.md1
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md16
-rw-r--r--locale/gitlab.pot30
-rw-r--r--qa/qa/page/project/settings/merge_request.rb9
-rw-r--r--rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb16
-rw-r--r--spec/controllers/admin/plan_limits_controller_spec.rb45
-rw-r--r--spec/factories/plan_limits.rb9
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb5
-rw-r--r--spec/features/merge_request/user_expands_diff_spec.rb3
-rw-r--r--spec/features/merge_request/user_views_auto_expanding_diff_spec.rb3
-rw-r--r--spec/frontend/releases/components/app_index_spec.js20
-rw-r--r--spec/frontend/releases/components/releases_pagination_graphql_spec.js4
-rw-r--r--spec/frontend/releases/components/releases_pagination_rest_spec.js2
-rw-r--r--spec/frontend/releases/stores/modules/list/actions_spec.js28
-rw-r--r--spec/routing/admin_routing_spec.rb6
-rw-r--r--spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb14
-rw-r--r--spec/views/admin/application_settings/_package_registry.html.haml_spec.rb65
39 files changed, 419 insertions, 87 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index b29d496a18a..00e8849e3c6 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-b670554eae8643f2072d3b4f6f7c5cd2b9ec8776
+b5937b10d1a386c392adb1ebced2d0c8cb038696
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index ba5342e993e..b8cf6ce478f 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -25,31 +25,16 @@ export default {
GlLink,
GlButton,
},
- props: {
- projectId: {
- type: String,
- required: true,
- },
- projectPath: {
- type: String,
- required: true,
- },
- documentationPath: {
- type: String,
- required: true,
- },
- illustrationPath: {
- type: String,
- required: true,
- },
- newReleasePath: {
- type: String,
- required: false,
- default: '',
- },
- },
computed: {
- ...mapState('list', ['isLoading', 'releases', 'hasError', 'pageInfo']),
+ ...mapState('list', [
+ 'documentationPath',
+ 'illustrationPath',
+ 'newReleasePath',
+ 'isLoading',
+ 'releases',
+ 'hasError',
+ 'pageInfo',
+ ]),
shouldRenderEmptyState() {
return !this.releases.length && !this.hasError && !this.isLoading;
},
@@ -65,15 +50,13 @@ export default {
created() {
this.fetchReleases({
page: getParameterByName('page'),
- projectId: this.projectId,
- projectPath: this.projectPath,
});
},
methods: {
...mapActions('list', ['fetchReleases']),
onChangePage(page) {
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
- this.fetchReleases({ page, projectId: this.projectId });
+ this.fetchReleases({ page });
},
},
};
diff --git a/app/assets/javascripts/releases/components/releases_pagination_graphql.vue b/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
index 50d2796b0bd..a4fe407a5bd 100644
--- a/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
+++ b/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
@@ -7,7 +7,7 @@ export default {
name: 'ReleasesPaginationGraphql',
components: { GlKeysetPagination },
computed: {
- ...mapState('list', ['projectPath', 'graphQlPageInfo']),
+ ...mapState('list', ['graphQlPageInfo']),
showPagination() {
return this.graphQlPageInfo.hasPreviousPage || this.graphQlPageInfo.hasNextPage;
},
@@ -16,11 +16,11 @@ export default {
...mapActions('list', ['fetchReleasesGraphQl']),
onPrev(before) {
historyPushState(buildUrlWithCurrentLocation(`?before=${before}`));
- this.fetchReleasesGraphQl({ projectPath: this.projectPath, before });
+ this.fetchReleasesGraphQl({ before });
},
onNext(after) {
historyPushState(buildUrlWithCurrentLocation(`?after=${after}`));
- this.fetchReleasesGraphQl({ projectPath: this.projectPath, after });
+ this.fetchReleasesGraphQl({ after });
},
},
};
diff --git a/app/assets/javascripts/releases/components/releases_pagination_rest.vue b/app/assets/javascripts/releases/components/releases_pagination_rest.vue
index 52e88f5dc9b..992cc4cd469 100644
--- a/app/assets/javascripts/releases/components/releases_pagination_rest.vue
+++ b/app/assets/javascripts/releases/components/releases_pagination_rest.vue
@@ -7,13 +7,13 @@ export default {
name: 'ReleasesPaginationRest',
components: { TablePagination },
computed: {
- ...mapState('list', ['projectId', 'pageInfo']),
+ ...mapState('list', ['pageInfo']),
},
methods: {
...mapActions('list', ['fetchReleasesRest']),
onChangePage(page) {
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
- this.fetchReleasesRest({ page, projectId: this.projectId });
+ this.fetchReleasesRest({ page });
},
},
};
diff --git a/app/assets/javascripts/releases/mount_index.js b/app/assets/javascripts/releases/mount_index.js
index c193cb9de9f..cd4fa5c5df5 100644
--- a/app/assets/javascripts/releases/mount_index.js
+++ b/app/assets/javascripts/releases/mount_index.js
@@ -21,9 +21,6 @@ export default () => {
graphqlMilestoneStats: Boolean(gon.features?.graphqlMilestoneStats),
},
}),
- render: h =>
- h(ReleaseListApp, {
- props: el.dataset,
- }),
+ render: h => h(ReleaseListApp),
});
};
diff --git a/app/assets/javascripts/releases/stores/modules/list/actions.js b/app/assets/javascripts/releases/stores/modules/list/actions.js
index 3d28ef23fe7..945b093b983 100644
--- a/app/assets/javascripts/releases/stores/modules/list/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/list/actions.js
@@ -23,7 +23,7 @@ export const requestReleases = ({ commit }) => commit(types.REQUEST_RELEASES);
*
* @param {String} projectId
*/
-export const fetchReleases = ({ dispatch, rootState }, { page = '1', projectId, projectPath }) => {
+export const fetchReleases = ({ dispatch, rootState, state }, { page = '1' }) => {
dispatch('requestReleases');
if (
@@ -35,7 +35,7 @@ export const fetchReleases = ({ dispatch, rootState }, { page = '1', projectId,
.query({
query: allReleasesQuery,
variables: {
- fullPath: projectPath,
+ fullPath: state.projectPath,
},
})
.then(response => {
@@ -44,7 +44,7 @@ export const fetchReleases = ({ dispatch, rootState }, { page = '1', projectId,
.catch(() => dispatch('receiveReleasesError'));
} else {
api
- .releases(projectId, { page })
+ .releases(state.projectId, { page })
.then(response => dispatch('receiveReleasesSuccess', response))
.catch(() => dispatch('receiveReleasesError'));
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 20819e82920..53525a4d877 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -731,7 +731,6 @@
.issuable-info-container {
flex: 1;
display: flex;
- padding-right: $gl-padding;
.issuable-main-info {
flex: 1 auto;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index a2f17678a8e..03603f637c8 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -14,7 +14,7 @@
}
.issue {
- padding: 10px 0 10px $gl-padding;
+ padding: 10px $gl-padding;
position: relative;
.title {
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index fc3d0053859..73f71f7ad55 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -170,6 +170,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def set_application_setting
@application_setting = ApplicationSetting.current_without_cache
+ @plans = Plan.all
end
def whitelist_query_limiting
diff --git a/app/controllers/admin/plan_limits_controller.rb b/app/controllers/admin/plan_limits_controller.rb
new file mode 100644
index 00000000000..2620db8aec5
--- /dev/null
+++ b/app/controllers/admin/plan_limits_controller.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+class Admin::PlanLimitsController < Admin::ApplicationController
+ include InternalRedirect
+
+ before_action :set_plan_limits
+
+ def create
+ redirect_path = referer_path(request) || general_admin_application_settings_path
+
+ respond_to do |format|
+ if @plan_limits.update(plan_limits_params)
+ format.json { head :ok }
+ format.html { redirect_to redirect_path, notice: _('Application limits saved successfully') }
+ else
+ format.json { head :bad_request }
+ format.html { render_update_error }
+ end
+ end
+ end
+
+ private
+
+ def set_plan_limits
+ @plan_limits = Plan.find(plan_limits_params[:plan_id]).actual_limits
+ end
+
+ def plan_limits_params
+ params.require(:plan_limits).permit(%i[
+ plan_id
+ conan_max_file_size
+ maven_max_file_size
+ npm_max_file_size
+ nuget_max_file_size
+ pypi_max_file_size
+ generic_packages_max_file_size
+ ])
+ end
+end
diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml
new file mode 100644
index 00000000000..257a90252cc
--- /dev/null
+++ b/app/views/admin/application_settings/_package_registry.html.haml
@@ -0,0 +1,50 @@
+- if Gitlab.config.packages.enabled
+ %section.settings.as-package.no-animate#js-package-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Package Registry')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _("Settings related to the use and experience of using GitLab's Package Registry.")
+
+ = render_if_exists 'admin/application_settings/ee_package_registry'
+
+ .settings-content
+ %h4
+ = _('Package file size limits')
+ %p
+ = _('Set limit to 0 to allow any file size.')
+ .scrolling-tabs-container.inner-page-scroll-tabs
+ - if @plans.size > 1
+ %ul.nav-links.scrolling-tabs.mobile-separator.nav.nav-tabs.mb-3
+ - @plans.each_with_index do |plan, index|
+ %li
+ = link_to admin_plan_limits_path(anchor: 'js-package-settings'), data: { target: "div#plan#{index}", action: "plan#{index}", toggle: 'tab'}, class: index == 0 ? 'active': '' do
+ = plan.name.capitalize
+ .tab-content
+ - @plans.each_with_index do |plan, index|
+ .tab-pane{ :id => "plan#{index}", class: index == 0 ? 'active': '' }
+ = form_for plan.actual_limits, url: admin_plan_limits_path(anchor: 'js-package-settings'), html: { class: 'fieldset-form' }, method: :post do |f|
+ = form_errors(plan)
+ %fieldset
+ = f.hidden_field(:plan_id, value: plan.id)
+ .form-group
+ = f.label :conan_max_file_size, _('Maximum Conan package file size in bytes'), class: 'label-bold'
+ = f.number_field :conan_max_file_size, class: 'form-control'
+ .form-group
+ = f.label :maven_max_file_size, _('Maximum Maven package file size in bytes'), class: 'label-bold'
+ = f.number_field :maven_max_file_size, class: 'form-control'
+ .form-group
+ = f.label :npm_max_file_size, _('Maximum NPM package file size in bytes'), class: 'label-bold'
+ = f.number_field :npm_max_file_size, class: 'form-control'
+ .form-group
+ = f.label :nuget_max_file_size, _('Maximum NuGet package file size in bytes'), class: 'label-bold'
+ = f.number_field :nuget_max_file_size, class: 'form-control'
+ .form-group
+ = f.label :pypi_max_file_size, _('Maximum PyPI package file size in bytes'), class: 'label-bold'
+ = f.number_field :pypi_max_file_size, class: 'form-control'
+ .form-group
+ = f.label :generic_packages_max_file_size, _('Generic package file size in bytes'), class: 'label-bold'
+ = f.number_field :generic_packages_max_file_size, class: 'form-control'
+ = f.submit _('Save %{name} size limits').html_safe % { name: plan.name.capitalize }, class: 'btn gl-button btn-success'
diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml
index 073a53d71fd..7a5997bbcfd 100644
--- a/app/views/projects/_merge_request_merge_checks_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_checks_settings.html.haml
@@ -21,6 +21,6 @@
.text-secondary
= s_('ProjectSettings|This introduces the risk of merging changes that will not pass the pipeline.')
.form-check.mb-2
- = form.check_box :only_allow_merge_if_all_discussions_are_resolved, class: 'form-check-input'
+ = form.check_box :only_allow_merge_if_all_discussions_are_resolved, class: 'form-check-input', data: { qa_selector: 'allow_merge_if_all_discussions_are_resolved_checkbox' }
= form.label :only_allow_merge_if_all_discussions_are_resolved, class: 'form-check-label' do
= s_('ProjectSettings|All discussions must be resolved')
diff --git a/changelogs/unreleased/240951-package-size-limits-ui.yml b/changelogs/unreleased/240951-package-size-limits-ui.yml
new file mode 100644
index 00000000000..5f98146bb88
--- /dev/null
+++ b/changelogs/unreleased/240951-package-size-limits-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Add admin UI for adjusting package file size limits
+merge_request: 40423
+author:
+type: added
diff --git a/changelogs/unreleased/250279-unnecessary-spacing-exists-in-issues-list.yml b/changelogs/unreleased/250279-unnecessary-spacing-exists-in-issues-list.yml
new file mode 100644
index 00000000000..e335bfa8ddd
--- /dev/null
+++ b/changelogs/unreleased/250279-unnecessary-spacing-exists-in-issues-list.yml
@@ -0,0 +1,5 @@
+---
+title: Remove an extra spacing from Dashboard Issues
+merge_request: 42459
+author: Takuya Noguchi
+type: fixed
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 1dd1149a9d2..bac8247de2e 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -141,6 +141,8 @@ namespace :admin do
get :status_delete_self_monitoring_project
end
+ resources :plan_limits, only: :create
+
resources :labels
resources :runners, only: [:index, :show, :update, :destroy] do
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index 6afdf31a481..5f8ab6683a9 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -167,6 +167,14 @@ added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic ports to be used are shown in the table below.
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 0aef42ec849..2ef555bff29 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -167,6 +167,14 @@ added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic ports to be used are shown in the table below.
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index 5583884e712..34b90964fbf 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -42,7 +42,7 @@ doesn't require you to provision and maintain a node.
To set up GitLab and its components to accommodate up to 2,000 users:
-1. [Configure the external load balancing node](#configure-the-load-balancer)
+1. [Configure the external load balancing node](#configure-the-external-load-balancer)
to handle the load balancing of the two GitLab application services nodes.
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure Redis](#configure-redis).
@@ -60,7 +60,7 @@ To set up GitLab and its components to accommodate up to 2,000 users:
storage. You can skip this step if you're not using GitLab Pages (which
requires NFS).
-## Configure the load balancer
+## Configure the external load balancer
NOTE: **Note:**
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/).
@@ -115,6 +115,14 @@ need to add a configuration to GitLab to configure SSL certificates. For
details about managing SSL certificates and configuring NGINX, see the
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic load balancer ports you should use are described in the following
@@ -568,7 +576,7 @@ On each node perform the following:
1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
To maintain uniformity of links across nodes, the `external_url`
on the application server should point to the external URL that users will use
- to access GitLab. This would be the URL of the [load balancer](#configure-the-load-balancer)
+ to access GitLab. This would be the URL of the [load balancer](#configure-the-external-load-balancer)
which will route traffic to the GitLab application server:
```ruby
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index ddc477c156f..be944586e43 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -162,6 +162,14 @@ added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic ports to be used are shown in the table below.
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 60521c05a6c..e812eed0227 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -167,6 +167,14 @@ added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic ports to be used are shown in the table below.
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index 319820d8268..6dfa588b092 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -162,6 +162,14 @@ added to GitLab to configure SSL certificates. See
[NGINX HTTPS documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
for details on managing SSL certificates and configuring NGINX.
+### Readiness checks
+
+Ensure the external load balancer only routes to working services with built
+in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
+all require [additional configuration](../monitoring/ip_whitelist.md)
+on the nodes being checked, otherwise, the external load balancer will not be able to
+connect.
+
### Ports
The basic ports to be used are shown in the table below.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 13b6fe5b379..e2c77073983 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -311,13 +311,20 @@ sudo adduser --disabled-login --gecos 'GitLab' git
## 6. Database
NOTE: **Note:**
-Starting from GitLab 12.1, only PostgreSQL is supported. Since GitLab 13.0, we require PostgreSQL 11+.
+Starting from GitLab 12.1, only PostgreSQL is supported. Since GitLab 13.0, we [require PostgreSQL 11+](requirements.md#postgresql-requirements).
1. Install the database packages:
```shell
sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib
```
+
+1. Verify the PostgreSQL version you have is supported by the version of GitLab you're
+ installing:
+
+ ```shell
+ psql --version
+ ```
1. Start the PostgreSQL service and confirm that the service is running:
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 921b6dc9b32..da0128fecc3 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -140,7 +140,6 @@ We highly recommend users to use the minimum PostgreSQL versions specified below
GitLab version | Minimum PostgreSQL version
-|-
10.0 | 9.6
-12.10 | 11
13.0 | 11
You must also ensure the `pg_trgm` and `btree_gist` extensions are [loaded into every
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index 607678bfe0e..b4867d33644 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -196,7 +196,9 @@ To set required pipeline configuration:
![Required pipeline](img/admin_required_pipeline.png)
-## Package Registry configuration **(PREMIUM ONLY)**
+## Package Registry configuration
+
+### NPM Forwarding **(PREMIUM ONLY)**
GitLab administrators can disable the forwarding of NPM requests to [npmjs.com](https://www.npmjs.com/).
@@ -208,3 +210,15 @@ To disable it:
1. Click **Save changes**.
![NPM package requests forwarding](img/admin_package_registry_npm_package_requests_forward.png)
+
+### Package file size limits
+
+GitLab administrators can adjust the maximum allowed file size for each package type.
+
+To set the maximum file size:
+
+1. Go to **Admin Area > Settings > CI/CD**.
+1. Expand the **Package Registry** section.
+1. Find the package type you would like to adjust.
+1. Enter the maximum file size, in bytes.
+1. Click **Save size limits**.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 3f4b8095997..249b2a9e671 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3101,6 +3101,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -11378,6 +11381,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -15403,6 +15409,21 @@ msgstr ""
msgid "Max size 15 MB"
msgstr ""
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
+
msgid "Maximum Users:"
msgstr ""
@@ -17862,6 +17883,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -21987,6 +22011,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -23048,6 +23075,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
diff --git a/qa/qa/page/project/settings/merge_request.rb b/qa/qa/page/project/settings/merge_request.rb
index 0092426b31f..ec8d73df1b3 100644
--- a/qa/qa/page/project/settings/merge_request.rb
+++ b/qa/qa/page/project/settings/merge_request.rb
@@ -15,6 +15,10 @@ module QA
element :radio_button_merge_ff
end
+ view 'app/views/projects/_merge_request_merge_checks_settings.html.haml' do
+ element :allow_merge_if_all_discussions_are_resolved_checkbox
+ end
+
def click_save_changes
click_element :save_merge_request_changes
end
@@ -23,6 +27,11 @@ module QA
click_element :radio_button_merge_ff
click_save_changes
end
+
+ def enable_merge_if_all_disscussions_are_resolved
+ click_element :allow_merge_if_all_discussions_are_resolved_checkbox
+ click_save_changes
+ end
end
end
end
diff --git a/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
index 36bcda527e8..9fdf52dac8b 100644
--- a/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
+++ b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
@@ -22,6 +22,7 @@ module RuboCop
def on_send(node)
distinct_count?(node) do |method_name, method_arguments|
next unless method_arguments && method_arguments.length >= 2
+ next if batch_set_to_false?(method_arguments[2])
next if allowed_foreign_key?(method_arguments[1])
add_offense(node, location: :selector, message: format(MSG, method_name))
@@ -37,6 +38,21 @@ module RuboCop
def allowed_foreign_keys
(cop_config['AllowedForeignKeys'] || []).map(&:to_s)
end
+
+ def batch_set_to_false?(options)
+ return false unless options.is_a?(RuboCop::AST::HashNode)
+
+ batch_set_to_false = false
+ options.each_pair do |key, value|
+ next unless value.boolean_type? && value.falsey_literal?
+ next unless key.type == :sym && key.value == :batch
+
+ batch_set_to_false = true
+ break
+ end
+
+ batch_set_to_false
+ end
end
end
end
diff --git a/spec/controllers/admin/plan_limits_controller_spec.rb b/spec/controllers/admin/plan_limits_controller_spec.rb
new file mode 100644
index 00000000000..2666925c2b7
--- /dev/null
+++ b/spec/controllers/admin/plan_limits_controller_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::PlanLimitsController do
+ let_it_be(:plan) { create(:plan) }
+ let_it_be(:plan_limits) { create(:plan_limits, plan: plan) }
+
+ describe 'POST create' do
+ let(:params) do
+ {
+ plan_limits: {
+ plan_id: plan.id,
+ conan_max_file_size: file_size, id: plan_limits.id
+ }
+ }
+ end
+
+ context 'with an authenticated admin user' do
+ let(:file_size) { 10.megabytes }
+
+ it 'updates the plan limits', :aggregate_failures do
+ sign_in(create(:admin))
+
+ post :create, params: params
+
+ expect(response).to redirect_to(general_admin_application_settings_path)
+ expect(plan_limits.reload.conan_max_file_size).to eq(file_size)
+ end
+ end
+
+ context 'without admin access' do
+ let(:file_size) { 1.megabytes }
+
+ it 'returns `not_found`' do
+ sign_in(create(:user))
+
+ post :create, params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(plan_limits.conan_max_file_size).not_to eq(file_size)
+ end
+ end
+ end
+end
diff --git a/spec/factories/plan_limits.rb b/spec/factories/plan_limits.rb
index 4aea09618d0..ae892307193 100644
--- a/spec/factories/plan_limits.rb
+++ b/spec/factories/plan_limits.rb
@@ -7,5 +7,14 @@ FactoryBot.define do
trait :default_plan do
plan factory: :default_plan
end
+
+ trait :with_package_file_sizes do
+ conan_max_file_size { 100 }
+ maven_max_file_size { 100 }
+ npm_max_file_size { 100 }
+ nuget_max_file_size { 100 }
+ pypi_max_file_size { 100 }
+ generic_packages_max_file_size { 100 }
+ end
end
end
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 6b8df8467e5..e705f2916da 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -7,11 +7,6 @@ RSpec.describe 'Expand and collapse diffs', :js do
let(:project) { create(:project, :repository) }
before do
- # Set the limits to those when these specs were written, to avoid having to
- # update the test repo every time we change them.
- allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes)
- allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes)
-
sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index b0cfa8d0d54..0e39cce13a1 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -7,9 +7,6 @@ RSpec.describe 'User expands diff', :js do
let(:merge_request) { create(:merge_request, source_branch: 'expand-collapse-files', source_project: project, target_project: project) }
before do
- allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes)
- allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes)
-
visit(diffs_project_merge_request_path(project, merge_request))
wait_for_requests
diff --git a/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb b/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb
index 585a389157e..1748f66c934 100644
--- a/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb
+++ b/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb
@@ -11,9 +11,6 @@ RSpec.describe 'User views diffs file-by-file', :js do
let(:user) { create(:user, view_diffs_file_by_file: true) }
before do
- allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes)
- allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes)
-
project.add_developer(user)
sign_in(user)
diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js
index 7c0b35f5eda..bcb87509cc3 100644
--- a/spec/frontend/releases/components/app_index_spec.js
+++ b/spec/frontend/releases/components/app_index_spec.js
@@ -27,15 +27,18 @@ describe('Releases App ', () => {
tagName: `${index}.00`,
}));
- const defaultProps = {
+ const defaultInitialState = {
projectId: 'gitlab-ce',
projectPath: 'gitlab-org/gitlab-ce',
documentationPath: 'help/releases',
illustrationPath: 'illustration/path',
};
- const createComponent = (propsData = defaultProps) => {
- const listModule = createListModule({});
+ const createComponent = (stateUpdates = {}) => {
+ const listModule = createListModule({
+ ...defaultInitialState,
+ ...stateUpdates,
+ });
fetchReleaseSpy = jest.spyOn(listModule.actions, 'fetchReleases');
@@ -51,7 +54,6 @@ describe('Releases App ', () => {
wrapper = shallowMount(ReleasesApp, {
store,
localVue,
- propsData,
});
};
@@ -68,13 +70,9 @@ describe('Releases App ', () => {
createComponent();
});
- it('calls fetchRelease with the page, project ID, and project path', () => {
+ it('calls fetchRelease with the page parameter', () => {
expect(fetchReleaseSpy).toHaveBeenCalledTimes(1);
- expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), {
- page: null,
- projectId: defaultProps.projectId,
- projectPath: defaultProps.projectPath,
- });
+ expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), { page: null });
});
});
@@ -156,7 +154,7 @@ describe('Releases App ', () => {
const newReleasePath = 'path/to/new/release';
beforeEach(() => {
- createComponent({ ...defaultProps, newReleasePath });
+ createComponent({ ...defaultInitialState, newReleasePath });
});
it('renders the "New release" button', () => {
diff --git a/spec/frontend/releases/components/releases_pagination_graphql_spec.js b/spec/frontend/releases/components/releases_pagination_graphql_spec.js
index ae50c6ae4a6..b01a28eb6c3 100644
--- a/spec/frontend/releases/components/releases_pagination_graphql_spec.js
+++ b/spec/frontend/releases/components/releases_pagination_graphql_spec.js
@@ -143,7 +143,7 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
it('calls fetchReleasesGraphQl with the correct after cursor', () => {
expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([
- [expect.anything(), { projectPath, after: cursors.endCursor }],
+ [expect.anything(), { after: cursors.endCursor }],
]);
});
@@ -161,7 +161,7 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
it('calls fetchReleasesGraphQl with the correct before cursor', () => {
expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([
- [expect.anything(), { projectPath, before: cursors.startCursor }],
+ [expect.anything(), { before: cursors.startCursor }],
]);
});
diff --git a/spec/frontend/releases/components/releases_pagination_rest_spec.js b/spec/frontend/releases/components/releases_pagination_rest_spec.js
index 7ff5200a289..4fd3e085fc9 100644
--- a/spec/frontend/releases/components/releases_pagination_rest_spec.js
+++ b/spec/frontend/releases/components/releases_pagination_rest_spec.js
@@ -59,7 +59,7 @@ describe('~/releases/components/releases_pagination_rest.vue', () => {
it('calls fetchReleasesRest with the correct page', () => {
expect(listModule.actions.fetchReleasesRest.mock.calls).toEqual([
- [expect.anything(), { projectId, page: newPage }],
+ [expect.anything(), { page: newPage }],
]);
});
diff --git a/spec/frontend/releases/stores/modules/list/actions_spec.js b/spec/frontend/releases/stores/modules/list/actions_spec.js
index 569c931757d..95e30659d6c 100644
--- a/spec/frontend/releases/stores/modules/list/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/list/actions_spec.js
@@ -23,11 +23,16 @@ describe('Releases State actions', () => {
let pageInfo;
let releases;
let graphqlReleasesResponse;
- let projectPath;
+
+ const projectPath = 'root/test-project';
+ const projectId = 19;
beforeEach(() => {
mockedState = {
- ...createState({}),
+ ...createState({
+ projectId,
+ projectPath,
+ }),
featureFlags: {
graphqlReleaseData: true,
graphqlReleasesPage: true,
@@ -38,7 +43,6 @@ describe('Releases State actions', () => {
pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
graphqlReleasesResponse = cloneDeep(originalGraphqlReleasesResponse);
- projectPath = 'root/test-project';
});
describe('requestReleases', () => {
@@ -51,7 +55,7 @@ describe('Releases State actions', () => {
describe('success', () => {
it('dispatches requestReleases and receiveReleasesSuccess', done => {
jest.spyOn(gqClient, 'query').mockImplementation(({ query, variables }) => {
- expect(query).toEqual(allReleasesQuery);
+ expect(query).toBe(allReleasesQuery);
expect(variables).toEqual({
fullPath: projectPath,
});
@@ -60,7 +64,7 @@ describe('Releases State actions', () => {
testAction(
fetchReleases,
- { projectPath },
+ {},
mockedState,
[],
[
@@ -83,7 +87,7 @@ describe('Releases State actions', () => {
testAction(
fetchReleases,
- { projectPath },
+ {},
mockedState,
[],
[
@@ -107,14 +111,14 @@ describe('Releases State actions', () => {
describe('success', () => {
it('dispatches requestReleases and receiveReleasesSuccess', done => {
jest.spyOn(api, 'releases').mockImplementation((id, options) => {
- expect(id).toEqual(1);
- expect(options.page).toEqual('1');
+ expect(id).toBe(projectId);
+ expect(options.page).toBe('1');
return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
});
testAction(
fetchReleases,
- { projectId: 1 },
+ {},
mockedState,
[],
[
@@ -132,13 +136,13 @@ describe('Releases State actions', () => {
it('dispatches requestReleases and receiveReleasesSuccess on page two', done => {
jest.spyOn(api, 'releases').mockImplementation((_, options) => {
- expect(options.page).toEqual('2');
+ expect(options.page).toBe('2');
return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
});
testAction(
fetchReleases,
- { page: '2', projectId: 1 },
+ { page: '2' },
mockedState,
[],
[
@@ -161,7 +165,7 @@ describe('Releases State actions', () => {
testAction(
fetchReleases,
- { projectId: null },
+ {},
mockedState,
[],
[
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 396b01edbfa..fedafff0d1b 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -178,3 +178,9 @@ RSpec.describe Admin::SessionsController, "routing" do
expect(post("/admin/session/destroy")).to route_to('admin/sessions#destroy')
end
end
+
+RSpec.describe Admin::PlanLimitsController, "routing" do
+ it "to #create" do
+ expect(post("/admin/plan_limits")).to route_to('admin/plan_limits#create')
+ end
+end
diff --git a/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb
index df8130b9c5d..8b6a2eac349 100644
--- a/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb
+++ b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb
@@ -21,11 +21,23 @@ RSpec.describe RuboCop::Cop::UsageData::DistinctCountByLargeForeignKey, type: :r
subject(:cop) { described_class.new(config) }
context 'when counting by disallowed key' do
- it 'register an offence' do
+ it 'registers an offence' do
inspect_source('distinct_count(Issue, :creator_id)')
expect(cop.offenses.size).to eq(1)
end
+
+ it 'does not register an offence when batch is false' do
+ inspect_source('distinct_count(Issue, :creator_id, batch: false)')
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it 'register an offence when batch is true' do
+ inspect_source('distinct_count(Issue, :creator_id, batch: true)')
+
+ expect(cop.offenses.size).to eq(1)
+ end
end
context 'when calling by allowed key' do
diff --git a/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb
new file mode 100644
index 00000000000..ef40829c29b
--- /dev/null
+++ b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'admin/application_settings/_package_registry' do
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:default_plan_limits) { create(:plan_limits, :default_plan, :with_package_file_sizes) }
+ let_it_be(:application_setting) { build(:application_setting) }
+ let(:page) { Capybara::Node::Simple.new(rendered) }
+
+ before do
+ assign(:application_setting, application_setting)
+ allow(view).to receive(:current_user) { admin }
+ allow(view).to receive(:expanded) { true }
+ end
+
+ subject { render partial: 'admin/application_settings/package_registry' }
+
+ context 'package file size limits' do
+ before do
+ assign(:plans, [default_plan_limits.plan])
+ end
+
+ it 'has fields for max package file sizes' do
+ subject
+
+ expect(rendered).to have_field('Maximum Conan package file size in bytes', type: 'number')
+ expect(page.find_field('Maximum Conan package file size in bytes').value).to eq(default_plan_limits.conan_max_file_size.to_s)
+
+ expect(rendered).to have_field('Maximum Maven package file size in bytes', type: 'number')
+ expect(page.find_field('Maximum Maven package file size in bytes').value).to eq(default_plan_limits.maven_max_file_size.to_s)
+
+ expect(rendered).to have_field('Maximum NPM package file size in bytes', type: 'number')
+ expect(page.find_field('Maximum NPM package file size in bytes').value).to eq(default_plan_limits.npm_max_file_size.to_s)
+
+ expect(rendered).to have_field('Maximum NuGet package file size in bytes', type: 'number')
+ expect(page.find_field('Maximum NuGet package file size in bytes').value).to eq(default_plan_limits.nuget_max_file_size.to_s)
+
+ expect(rendered).to have_field('Maximum PyPI package file size in bytes', type: 'number')
+ expect(page.find_field('Maximum PyPI package file size in bytes').value).to eq(default_plan_limits.pypi_max_file_size.to_s)
+ end
+
+ it 'does not display the plan name when there is only one plan' do
+ subject
+
+ expect(page).not_to have_content('Default')
+ end
+ end
+
+ context 'with multiple plans' do
+ let_it_be(:plan) { create(:plan, name: 'Gold') }
+ let_it_be(:gold_plan_limits) { create(:plan_limits, :with_package_file_sizes, plan: plan) }
+
+ before do
+ assign(:plans, [default_plan_limits.plan, gold_plan_limits.plan])
+ end
+
+ it 'displays the plan name when there is more than one plan' do
+ subject
+
+ expect(page).to have_content('Default')
+ expect(page).to have_content('Gold')
+ end
+ end
+end