Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0115b63f64
commit
a8b87b4fe0
39 changed files with 419 additions and 87 deletions
|
@ -1 +1 @@
|
|||
b670554eae8643f2072d3b4f6f7c5cd2b9ec8776
|
||||
b5937b10d1a386c392adb1ebced2d0c8cb038696
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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 });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -21,9 +21,6 @@ export default () => {
|
|||
graphqlMilestoneStats: Boolean(gon.features?.graphqlMilestoneStats),
|
||||
},
|
||||
}),
|
||||
render: h =>
|
||||
h(ReleaseListApp, {
|
||||
props: el.dataset,
|
||||
}),
|
||||
render: h => h(ReleaseListApp),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
|
|
|
@ -731,7 +731,6 @@
|
|||
.issuable-info-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
padding-right: $gl-padding;
|
||||
|
||||
.issuable-main-info {
|
||||
flex: 1 auto;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
}
|
||||
|
||||
.issue {
|
||||
padding: 10px 0 10px $gl-padding;
|
||||
padding: 10px $gl-padding;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
|
|
|
@ -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
|
||||
|
|
39
app/controllers/admin/plan_limits_controller.rb
Normal file
39
app/controllers/admin/plan_limits_controller.rb
Normal file
|
@ -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
|
|
@ -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'
|
|
@ -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')
|
||||
|
|
5
changelogs/unreleased/240951-package-size-limits-ui.yml
Normal file
5
changelogs/unreleased/240951-package-size-limits-ui.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add admin UI for adjusting package file size limits
|
||||
merge_request: 40423
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove an extra spacing from Dashboard Issues
|
||||
merge_request: 42459
|
||||
author: Takuya Noguchi
|
||||
type: fixed
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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**.
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
45
spec/controllers/admin/plan_limits_controller_spec.rb
Normal file
45
spec/controllers/admin/plan_limits_controller_spec.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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 }],
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -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 }],
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
[],
|
||||
[
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in a new issue