Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-30 15:08:54 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-30 15:08:54 +0300
commit50ae4065530c4eafbeb7c5ff2c462c48c02947ca (patch)
treea88b718bd281c58fcd9e60fd49585e5ca1dca26c
parentbe37a0ee5e3e3dbb967266248f0f46f14a9931e2 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitignore1
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue67
-rw-r--r--app/assets/javascripts/pages/projects/wikis/wikis.js2
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml10
-rw-r--r--app/views/admin/application_settings/general.html.haml2
-rw-r--r--app/views/admin/broadcast_messages/_form.html.haml28
-rw-r--r--app/views/import/shared/_new_project_form.html.haml2
-rw-r--r--app/views/layouts/_broadcast.html.haml3
-rw-r--r--changelogs/unreleased/197932-add-package-tags-display-to-package-list-page.yml5
-rw-r--r--changelogs/unreleased/198464-add-can_create_merge_request_in-to-project-api-response.yml5
-rw-r--r--changelogs/unreleased/21371-auto-generated-wiki-commit-message-having-html-encoded-entities.yml5
-rw-r--r--changelogs/unreleased/28872-admin-area-s-account-and-limit-fields-could-be-improved.yml5
-rw-r--r--changelogs/unreleased/jivanvl-fix-charts-shrinkage.yml5
-rw-r--r--changelogs/unreleased/mr-approvals-anchors.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-add-broadcast-types.yml5
-rw-r--r--changelogs/unreleased/pages-version-v1-15-0.yml5
-rw-r--r--changelogs/unreleased/prevent-project-path-namespace-overflow-during-import.yml5
-rw-r--r--doc/.linting/vale/styles/gitlab/Contractions.yml76
-rw-r--r--doc/api/projects.md12
-rw-r--r--doc/development/contributing/merge_request_workflow.md4
-rw-r--r--doc/development/documentation/styleguide.md6
-rw-r--r--doc/development/rake_tasks.md11
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/tasks/gitlab/seed/group_seed.rake233
-rw-r--r--locale/gitlab.pot27
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb10
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb12
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap94
-rw-r--r--spec/frontend/monitoring/components/dashboard_template_spec.js45
-rw-r--r--spec/requests/api/projects_spec.rb2
-rw-r--r--spec/tasks/gitlab/seed/group_seed_rake_spec.rb26
32 files changed, 652 insertions, 72 deletions
diff --git a/.gitignore b/.gitignore
index 5cdab272055..b3e6cbae96b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,4 @@ jsdoc/
/qa/.rakeTasks
webpack-dev-server.json
/.nvimrc
+.solargraph.yml
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 850e742404b..141f2e805be 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.14.0
+1.15.0
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 0cdda48f1e5..5c643a864d6 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -532,44 +532,41 @@ export default {
:show-panels="showPanels"
:collapse-group="collapseGroup(groupData.key)"
>
- <div v-if="!groupSingleEmptyState(groupData.key)">
- <vue-draggable
- :value="groupData.panels"
- group="metrics-dashboard"
- :component-data="{ attrs: { class: 'row mx-0 w-100' } }"
- :disabled="!isRearrangingPanels"
- @input="updatePanels(groupData.key, $event)"
+ <vue-draggable
+ v-if="!groupSingleEmptyState(groupData.key)"
+ :value="groupData.panels"
+ group="metrics-dashboard"
+ :component-data="{ attrs: { class: 'row mx-0 w-100' } }"
+ :disabled="!isRearrangingPanels"
+ @input="updatePanels(groupData.key, $event)"
+ >
+ <div
+ v-for="(graphData, graphIndex) in groupData.panels"
+ :key="`panel-type-${graphIndex}`"
+ class="col-12 col-lg-6 px-2 mb-2 draggable"
+ :class="{ 'draggable-enabled': isRearrangingPanels }"
>
- <div
- v-for="(graphData, graphIndex) in groupData.panels"
- :key="`panel-type-${graphIndex}`"
- class="col-12 col-lg-6 px-2 mb-2 draggable"
- :class="{ 'draggable-enabled': isRearrangingPanels }"
- >
- <div class="position-relative draggable-panel js-draggable-panel">
- <div
- v-if="isRearrangingPanels"
- class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end"
- @click="removePanel(groupData.key, groupData.panels, graphIndex)"
- >
- <a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')">
- <icon name="close" />
- </a>
- </div>
-
- <panel-type
- :clipboard-text="
- generateLink(groupData.group, graphData.title, graphData.y_label)
- "
- :graph-data="graphData"
- :alerts-endpoint="alertsEndpoint"
- :prometheus-alerts-available="prometheusAlertsAvailable"
- :index="`${index}-${graphIndex}`"
- />
+ <div class="position-relative draggable-panel js-draggable-panel">
+ <div
+ v-if="isRearrangingPanels"
+ class="draggable-remove js-draggable-remove p-2 w-100 position-absolute d-flex justify-content-end"
+ @click="removePanel(groupData.key, groupData.panels, graphIndex)"
+ >
+ <a class="mx-2 p-2 draggable-remove-link" :aria-label="__('Remove')">
+ <icon name="close" />
+ </a>
</div>
+
+ <panel-type
+ :clipboard-text="generateLink(groupData.group, graphData.title, graphData.y_label)"
+ :graph-data="graphData"
+ :alerts-endpoint="alertsEndpoint"
+ :prometheus-alerts-available="prometheusAlertsAvailable"
+ :index="`${index}-${graphIndex}`"
+ />
</div>
- </vue-draggable>
- </div>
+ </div>
+ </vue-draggable>
<div v-else class="py-5 col col-sm-10 col-md-8 col-lg-7 col-xl-6">
<group-empty-state
ref="empty-group"
diff --git a/app/assets/javascripts/pages/projects/wikis/wikis.js b/app/assets/javascripts/pages/projects/wikis/wikis.js
index 80b62859134..6b02a074abf 100644
--- a/app/assets/javascripts/pages/projects/wikis/wikis.js
+++ b/app/assets/javascripts/pages/projects/wikis/wikis.js
@@ -40,7 +40,7 @@ export default class Wikis {
// Replace hyphens with spaces
if (title) title = title.replace(/-+/g, ' ');
- const newCommitMessage = sprintf(this.commitMessageI18n, { pageTitle: title });
+ const newCommitMessage = sprintf(this.commitMessageI18n, { pageTitle: title }, false);
this.commitMessageInput.value = newCommitMessage;
}
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index 4ab0ec90735..aa377886edc 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -8,20 +8,20 @@
= f.label :gravatar_enabled, class: 'form-check-label' do
= _('Gravatar enabled')
.form-group
- = f.label :default_projects_limit, class: 'label-bold'
- = f.number_field :default_projects_limit, class: 'form-control'
+ = f.label :default_projects_limit, _('Default projects limit'), class: 'label-bold'
+ = f.number_field :default_projects_limit, class: 'form-control', title: _('Maximum number of projects.'), data: { toggle: 'tooltip', container: 'body' }
.form-group
= f.label :max_attachment_size, _('Maximum attachment size (MB)'), class: 'label-bold'
- = f.number_field :max_attachment_size, class: 'form-control'
+ = f.number_field :max_attachment_size, class: 'form-control', title: _('Maximum size of individual attachments in comments.'), data: { toggle: 'tooltip', container: 'body' }
= render_if_exists 'admin/application_settings/repository_size_limit_setting', form: f
.form-group
= f.label :receive_max_input_size, _('Maximum push size (MB)'), class: 'label-light'
- = f.number_field :receive_max_input_size, class: 'form-control qa-receive-max-input-size-field'
+ = f.number_field :receive_max_input_size, class: 'form-control qa-receive-max-input-size-field', title: _('Maximum size limit for a single commit.'), data: { toggle: 'tooltip', container: 'body' }
.form-group
= f.label :session_expire_delay, _('Session duration (minutes)'), class: 'label-light'
- = f.number_field :session_expire_delay, class: 'form-control'
+ = f.number_field :session_expire_delay, class: 'form-control', title: _('Maximum duration of a session.'), data: { toggle: 'tooltip', container: 'body' }
%span.form-text.text-muted#session_expire_delay_help_block= _('GitLab restart is required to apply changes.')
= render_if_exists 'admin/application_settings/personal_access_token_expiration_policy', form: f
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index b9f49fdc9de..94048060767 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -20,7 +20,7 @@
%button.btn.js-settings-toggle{ type: 'button' }
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
- = _('Session expiration, projects limit and attachment size.')
+ = _('Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan.')
.settings-content
= render 'account_and_limit'
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index 33b56655206..9577a2a79df 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -5,15 +5,14 @@
= render_broadcast_message(@broadcast_message)
- else
Your message here
-- if Feature.enabled?(:broadcast_notification_type)
- .d-flex.justify-content-center
- .broadcast-notification-message.preview.js-broadcast-notification-message-preview.mt-2{ class: ('hidden' unless @broadcast_message.notification? ) }
- = sprite_icon('bullhorn', size: 16, css_class:'vertical-align-text-top')
- .js-broadcast-message-preview
- - if @broadcast_message.message.present?
- = render_broadcast_message(@broadcast_message)
- - else
- Your message here
+.d-flex.justify-content-center
+ .broadcast-notification-message.preview.js-broadcast-notification-message-preview.mt-2{ class: ('hidden' unless @broadcast_message.notification? ) }
+ = sprite_icon('bullhorn', size: 16, css_class:'vertical-align-text-top')
+ .js-broadcast-message-preview
+ - if @broadcast_message.message.present?
+ = render_broadcast_message(@broadcast_message)
+ - else
+ Your message here
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form js-quick-submit js-requires-input'} do |f|
= form_errors(@broadcast_message)
@@ -26,12 +25,11 @@
required: true,
dir: 'auto',
data: { preview_path: preview_admin_broadcast_messages_path }
- - if Feature.enabled?(:broadcast_notification_type)
- .form-group.row
- .col-sm-2.col-form-label
- = f.label :broadcast_type, _('Type')
- .col-sm-10
- = f.select :broadcast_type, broadcast_type_options, {}, class: 'form-control js-broadcast-message-type'
+ .form-group.row
+ .col-sm-2.col-form-label
+ = f.label :broadcast_type, _('Type')
+ .col-sm-10
+ = f.select :broadcast_type, broadcast_type_options, {}, class: 'form-control js-broadcast-message-type'
.form-group.row.js-broadcast-message-background-color-form-group{ class: ('hidden' unless @broadcast_message.banner? ) }
.col-sm-2.col-form-label
= f.label :color, _("Background color")
diff --git a/app/views/import/shared/_new_project_form.html.haml b/app/views/import/shared/_new_project_form.html.haml
index 4d13d4f2869..35059229a55 100644
--- a/app/views/import/shared/_new_project_form.html.haml
+++ b/app/views/import/shared/_new_project_form.html.haml
@@ -10,7 +10,7 @@
.input-group-prepend.flex-shrink-0.has-tooltip{ title: root_url }
.input-group-text
= root_url
- = select_tag :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), class: 'select2 js-select-namespace', tabindex: 1
+ = select_tag :namespace_id, namespaces_options(namespace_id_from(params) || :current_user, display_path: true, extra_group: namespace_id_from(params)), class: 'select2 js-select-namespace block-truncated', tabindex: 1
- else
.input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
.input-group-text.border-0
diff --git a/app/views/layouts/_broadcast.html.haml b/app/views/layouts/_broadcast.html.haml
index 9d7ad249ac8..4c4fc6411b8 100644
--- a/app/views/layouts/_broadcast.html.haml
+++ b/app/views/layouts/_broadcast.html.haml
@@ -1,4 +1,3 @@
- current_broadcast_banner_messages.each do |message|
= broadcast_message(message)
-- if Feature.enabled?(:broadcast_notification_type)
- = broadcast_message(current_broadcast_notification_message)
+= broadcast_message(current_broadcast_notification_message)
diff --git a/changelogs/unreleased/197932-add-package-tags-display-to-package-list-page.yml b/changelogs/unreleased/197932-add-package-tags-display-to-package-list-page.yml
new file mode 100644
index 00000000000..d0db5339c2b
--- /dev/null
+++ b/changelogs/unreleased/197932-add-package-tags-display-to-package-list-page.yml
@@ -0,0 +1,5 @@
+---
+title: Displays package tags next to the name on the new package list page
+merge_request: 23675
+author:
+type: added
diff --git a/changelogs/unreleased/198464-add-can_create_merge_request_in-to-project-api-response.yml b/changelogs/unreleased/198464-add-can_create_merge_request_in-to-project-api-response.yml
new file mode 100644
index 00000000000..9cc9643d0c8
--- /dev/null
+++ b/changelogs/unreleased/198464-add-can_create_merge_request_in-to-project-api-response.yml
@@ -0,0 +1,5 @@
+---
+title: Add can_create_merge_request_in to /project/:id API response
+merge_request: 23577
+author:
+type: added
diff --git a/changelogs/unreleased/21371-auto-generated-wiki-commit-message-having-html-encoded-entities.yml b/changelogs/unreleased/21371-auto-generated-wiki-commit-message-having-html-encoded-entities.yml
new file mode 100644
index 00000000000..a588b60864a
--- /dev/null
+++ b/changelogs/unreleased/21371-auto-generated-wiki-commit-message-having-html-encoded-entities.yml
@@ -0,0 +1,5 @@
+---
+title: Auto generated wiki commit message containing HTML encoded entities
+merge_request: 21371
+author: 2knal
+type: other
diff --git a/changelogs/unreleased/28872-admin-area-s-account-and-limit-fields-could-be-improved.yml b/changelogs/unreleased/28872-admin-area-s-account-and-limit-fields-could-be-improved.yml
new file mode 100644
index 00000000000..64142fd7f88
--- /dev/null
+++ b/changelogs/unreleased/28872-admin-area-s-account-and-limit-fields-could-be-improved.yml
@@ -0,0 +1,5 @@
+---
+title: Add clarifying content to account fields
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/jivanvl-fix-charts-shrinkage.yml b/changelogs/unreleased/jivanvl-fix-charts-shrinkage.yml
new file mode 100644
index 00000000000..9cc1a91c442
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-fix-charts-shrinkage.yml
@@ -0,0 +1,5 @@
+---
+title: Fix custom charts in monitoring dashboard shrinking
+merge_request: 23649
+author:
+type: fixed
diff --git a/changelogs/unreleased/mr-approvals-anchors.yml b/changelogs/unreleased/mr-approvals-anchors.yml
new file mode 100644
index 00000000000..72f6d7b5bc3
--- /dev/null
+++ b/changelogs/unreleased/mr-approvals-anchors.yml
@@ -0,0 +1,5 @@
+---
+title: Update links related to MR approvals in UI
+merge_request: 23948
+author:
+type: other
diff --git a/changelogs/unreleased/nicolasdular-add-broadcast-types.yml b/changelogs/unreleased/nicolasdular-add-broadcast-types.yml
new file mode 100644
index 00000000000..44345f74e14
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-add-broadcast-types.yml
@@ -0,0 +1,5 @@
+---
+title: Add broadcast types to broadcast messages
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/pages-version-v1-15-0.yml b/changelogs/unreleased/pages-version-v1-15-0.yml
new file mode 100644
index 00000000000..13b5764d612
--- /dev/null
+++ b/changelogs/unreleased/pages-version-v1-15-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade Pages to 1.15.0
+merge_request: 24043
+author:
+type: added
diff --git a/changelogs/unreleased/prevent-project-path-namespace-overflow-during-import.yml b/changelogs/unreleased/prevent-project-path-namespace-overflow-during-import.yml
new file mode 100644
index 00000000000..e48d44d0f5d
--- /dev/null
+++ b/changelogs/unreleased/prevent-project-path-namespace-overflow-during-import.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent project path namespace overflow during import
+merge_request: 24042
+author: George Tsiolis
+type: fixed
diff --git a/doc/.linting/vale/styles/gitlab/Contractions.yml b/doc/.linting/vale/styles/gitlab/Contractions.yml
new file mode 100644
index 00000000000..0f31f6b6aa9
--- /dev/null
+++ b/doc/.linting/vale/styles/gitlab/Contractions.yml
@@ -0,0 +1,76 @@
+---
+# `extends` indicates the Vale extension point being used.
+# Full list of styles: https://errata-ai.github.io/vale/styles/
+extends: substitution
+
+# Substitution rules can display the matched and suggested strings in the
+# message shown to the user. The first use of %s prints the suggested option,
+# and the second use of %s displays what was found in the text.
+message: Use "%s" instead of "%s" in most cases.
+
+# Should a result be flagged as a suggestion, warning, or error?
+# Results that fall below the MinAlertLevel set in
+# https://gitlab.com/gitlab-org/gitlab/blob/master/.vale.ini won't be shown.
+level: suggestion
+
+# Should a match be case-insensitive or case-sensitive?
+# Acceptable values are 'true' or 'false'
+ignorecase: true
+
+# Should this rule be limited to a specific scope? If yes, uncomment the line.
+# Possible scopes: https://errata-ai.github.io/vale/formats/#available-scopes
+# scope: heading
+
+# Should this rule ignore normal word boundaries, such as \b ?
+# Acceptable values are 'true' or 'false'
+nonword: false
+
+# What is the source for this rule?
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
+
+# The 'swap' section provides a list of values, one per line, in the form of
+# $bad: $good
+swap:
+
+ # Common contractions are ok
+ it is: it's
+ can not: can't
+ cannot: can't
+ do not: don't
+ have not: haven't
+ that is: that's
+ we are: we're
+ will not: won't
+ would not: wouldn't
+ you are: you're
+ you have: you've
+
+ # Uncommon contractions are not ok
+ aren't: are not
+ couldn't: could not
+ didn't: did not
+ doesn't: does not
+ hasn't: has not
+ how'll: how will
+ how's: how is
+ isn't: is not
+ it'll: it will
+ shouldn't: should not
+ that'll: that will
+ they'll: they will
+ they're: they are
+ wasn't: was not
+ weren't: were not
+ we'll: we will
+ we've: we have
+ what's: what is
+ what'll: what will
+ when's: when is
+ when'll: when will
+ where's: where is
+ where'll: where will
+ who's: who is
+ who'll: who will
+ why's: why is
+ why'll: why will
+
diff --git a/doc/api/projects.md b/doc/api/projects.md
index d67d8949571..ad1cc4ea1b7 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -129,6 +129,7 @@ When the user is authenticated and `simple` is not set this returns something li
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -205,6 +206,7 @@ When the user is authenticated and `simple` is not set this returns something li
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -371,6 +373,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -447,6 +450,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -584,6 +588,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -657,6 +662,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -774,6 +780,7 @@ GET /projects/:id
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"container_expiration_policy": {
@@ -1260,6 +1267,7 @@ Example responses:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -1342,6 +1350,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -1431,6 +1440,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -1594,6 +1604,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
@@ -1702,6 +1713,7 @@ Example response:
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
+ "can_create_merge_request_in": true,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index e839ae0ea3a..8ba6cbf657d 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -15,8 +15,7 @@ to be marked as `Accepting Merge Requests`. Please include screenshots or
wireframes of the proposed feature if it will also change the UI.
Merge requests should be submitted to the appropriate project at GitLab.com, for example
-[GitLab CE](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests),
-[GitLab EE](https://gitlab.com/gitlab-org/gitlab/merge_requests),
+[GitLab](https://gitlab.com/gitlab-org/gitlab/merge_requests),
[GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/merge_requests),
[GitLab Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests), etc.
@@ -227,6 +226,7 @@ requirements.
1. [Changelog entry added](../changelog.md), if necessary.
1. Reviewed by relevant (UX/FE/BE/tech writing) reviewers and all concerns are addressed.
1. Merged by a project maintainer.
+1. Create an issue in the [infrastructure issue tracker](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues) to inform the Infrastructure department when your contribution is changing default settings or introduces a new setting, if relevant.
1. Confirmed to be working in the [Canary stage](https://about.gitlab.com/handbook/engineering/#canary-testing) or on GitLab.com once the contribution is deployed.
1. Added to the [release post](https://about.gitlab.com/handbook/marketing/blog/release-posts/),
if relevant.
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 063f2b74ce2..b361648b2f0 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -771,6 +771,9 @@ nicely on different mobile devices.
To make things easier for the user, always add a full code block for things that can be
useful to copy and paste, as they can easily do it with the button on code blocks.
- Add a blank line above and below code blocks.
+- When providing a shell command and its output, prefix the shell command with `$` and
+ leave a blank line between the command and the output.
+- When providing a command without output, don't prefix the shell command with `$`.
- For regular code blocks, always use a highlighting class corresponding to the
language for better readability. Examples:
@@ -795,7 +798,8 @@ nicely on different mobile devices.
- To display raw Markdown instead of rendered Markdown, you can use triple backticks
with `md`, like the `Markdown code` example above, unless you want to include triple
backticks in the code block as well. In that case, use triple tildes (`~~~`) instead.
-- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers) is available for many languages.
+- [Syntax highlighting for code blocks](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers)
+ is available for many languages. Use `shell` instead of `bash` or `sh` for shell output.
- For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks).
## GitLab SVG icons
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index ff978ee2899..d9b2ace1b5b 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -54,6 +54,17 @@ By default, this seeds an average of 10 issues per week for the last 52 weeks
per project. All issues will also be randomly labeled with team, type, severity,
and priority.
+#### Seeding groups with sub-groups
+
+You can seed groups with sub-groups that contain milestones/projects/issues
+with the `gitlab:seed:group_seed` task:
+
+```shell
+bin/rake "gitlab:seed:group_seed[subgroup_depth, username]"
+```
+
+Group are additionally seeded with epics if GitLab instance has epics feature available.
+
### Automation
If you're very sure that you want to **wipe the current database** and refill
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 95d57b49453..32a5f3ce33d 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -132,6 +132,10 @@ module API
expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
+ expose(:can_create_merge_request_in) do |project, options|
+ Ability.allowed?(options[:current_user], :create_merge_request_in, project)
+ end
+
expose(:issues_access_level) { |project, options| project.project_feature.string_access_level(:issues) }
expose(:repository_access_level) { |project, options| project.project_feature.string_access_level(:repository) }
expose(:merge_requests_access_level) { |project, options| project.project_feature.string_access_level(:merge_requests) }
diff --git a/lib/tasks/gitlab/seed/group_seed.rake b/lib/tasks/gitlab/seed/group_seed.rake
new file mode 100644
index 00000000000..bc705c94422
--- /dev/null
+++ b/lib/tasks/gitlab/seed/group_seed.rake
@@ -0,0 +1,233 @@
+# frozen_string_literal: true
+
+# Seed test groups with:
+# 1. 2 Subgroups per level
+# 1. 2 Users & group members per group
+# 1. 2 Epics, 2 Milestones & 2 Projects per group
+# 1. Project issues
+#
+# It also assigns each project's issue with one of group's or ascendants
+# groups milestone & epic.
+#
+# @param subgroups_depth - number of subgroup levels
+# @param username - user creating subgroups (i.e. GitLab admin)
+#
+# @example
+# bundle exec rake "gitlab:seed:group_seed[5, root]"
+#
+namespace :gitlab do
+ namespace :seed do
+ desc 'Seed groups with sub-groups/projects/epics/milestones for Group Import testing'
+ task :group_seed, [:subgroups_depth, :username] => :gitlab_environment do |_t, args|
+ require 'sidekiq/testing'
+
+ GroupSeeder.new(
+ subgroups_depth: args.subgroups_depth,
+ username: args.username
+ ).seed
+ end
+ end
+end
+
+class GroupSeeder
+ PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-test.git'
+
+ attr_reader :all_group_ids
+
+ def initialize(subgroups_depth:, username:)
+ @subgroups_depth = subgroups_depth.to_i
+ @user = User.find_by_username(username)
+ @group_names = Set.new
+ @resource_count = 2
+ @all_groups = {}
+ @all_group_ids = []
+ end
+
+ def seed
+ create_groups
+
+ puts 'Done!'
+ end
+
+ def create_groups
+ create_root_group
+ create_sub_groups
+ create_users_and_members
+ create_epics if Gitlab.ee?
+ create_labels
+ create_milestones
+
+ Sidekiq::Testing.inline! do
+ create_projects
+ end
+ end
+
+ def create_users_and_members
+ all_group_ids.each do |group_id|
+ @resource_count.times do |_|
+ user = create_user
+ create_member(user.id, group_id)
+ end
+ end
+ end
+
+ def create_root_group
+ root_group = ::Groups::CreateService.new(@user, group_params).execute
+
+ track_group_id(1, root_group.id)
+ end
+
+ def create_sub_groups
+ (2..@subgroups_depth).each do |level|
+ parent_level = level - 1
+ current_level = level
+ parent_groups = @all_groups[parent_level]
+
+ parent_groups.each do |parent_id|
+ @resource_count.times do |_|
+ sub_group = ::Groups::CreateService.new(@user, group_params(parent_id: parent_id)).execute
+
+ track_group_id(current_level, sub_group.id)
+ end
+ end
+ end
+ end
+
+ def track_group_id(depth_level, group_id)
+ @all_groups[depth_level] ||= []
+ @all_groups[depth_level] << group_id
+ @all_group_ids << group_id
+ end
+
+ def group_params(parent_id: nil)
+ name = unique_name
+
+ {
+ name: name,
+ path: name,
+ parent_id: parent_id
+ }
+ end
+
+ def unique_name
+ name = ffaker_name
+ name = ffaker_name until @group_names.add?(name)
+ name
+ end
+
+ def ffaker_name
+ FFaker::Lorem.characters(5)
+ end
+
+ def create_user
+ User.create!(
+ username: FFaker::Internet.user_name,
+ name: FFaker::Name.name,
+ email: FFaker::Internet.email,
+ confirmed_at: DateTime.now,
+ password: Devise.friendly_token
+ )
+ end
+
+ def create_member(user_id, group_id)
+ roles = Gitlab::Access.values
+
+ GroupMember.create(user_id: user_id, access_level: roles.sample, source_id: group_id)
+ end
+
+ def create_epics
+ all_group_ids.each do |group_id|
+ @resource_count.times do |_|
+ group = Group.find(group_id)
+
+ epic_params = {
+ title: FFaker::Lorem.sentence(6),
+ description: FFaker::Lorem.paragraphs(3).join("\n\n"),
+ author: group.users.sample,
+ group: group
+ }
+
+ Epic.create!(epic_params)
+ end
+ end
+ end
+
+ def create_labels
+ all_group_ids.each do |group_id|
+ @resource_count.times do |_|
+ group = Group.find(group_id)
+ label_title = FFaker::Product.brand
+
+ Labels::CreateService.new(title: label_title, color: "##{Digest::MD5.hexdigest(label_title)[0..5]}").execute(group: group)
+ end
+ end
+ end
+
+ def create_milestones
+ all_group_ids.each do |group_id|
+ @resource_count.times do |i|
+ group = Group.find(group_id)
+
+ milestone_params = {
+ title: "v#{i}.0",
+ description: FFaker::Lorem.sentence,
+ state: [:active, :closed].sample
+ }
+
+ Milestones::CreateService.new(group, group.members.sample, milestone_params).execute
+ end
+ end
+ end
+
+ def create_projects
+ all_group_ids.each do |group_id|
+ group = Group.find(group_id)
+
+ @resource_count.times do |i|
+ _, project_path = PROJECT_URL.split('/')[-2..-1]
+
+ project_path.gsub!('.git', '')
+
+ params = {
+ import_url: PROJECT_URL,
+ namespace_id: group.id,
+ name: project_path.titleize + FFaker::Lorem.characters(10),
+ description: FFaker::Lorem.sentence,
+ visibility_level: 0,
+ skip_disk_validation: true
+ }
+
+ project = nil
+
+ Sidekiq::Worker.skipping_transaction_check do
+ project = ::Projects::CreateService.new(@user, params).execute
+ project.send(:_run_after_commit_queue)
+ project.import_state.send(:_run_after_commit_queue)
+ project.repository.expire_all_method_caches
+ end
+
+ create_project_issues(project)
+ assign_issues_to_epics_and_milestones(project)
+ end
+ end
+ end
+
+ def create_project_issues(project)
+ seeder = Quality::Seeders::Issues.new(project: project)
+ seeder.seed(backfill_weeks: 2, average_issues_per_week: 2)
+ end
+
+ def assign_issues_to_epics_and_milestones(project)
+ group_ids = project.group.self_and_ancestors.map(&:id)
+
+ project.issues.each do |issue|
+ issue_params = {
+ milestone: Milestone.where(group: group_ids).sample
+ }
+
+ issue_params[:epic] = Epic.where(group: group_ids).sample if Gitlab.ee?
+
+ issue.update(issue_params)
+ end
+ end
+end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 81442d3fc7d..adc979efd1d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -6035,6 +6035,9 @@ msgstr ""
msgid "Default project deletion protection"
msgstr ""
+msgid "Default projects limit"
+msgstr ""
+
msgid "Default: Directly import the Google Code email address or username"
msgstr ""
@@ -10470,6 +10473,9 @@ msgstr ""
msgid "Is blocked by"
msgstr ""
+msgid "Is this GitLab trial for your company?"
+msgstr ""
+
msgid "Is using license seat:"
msgstr ""
@@ -11628,6 +11634,9 @@ msgstr ""
msgid "Maximum delay (Minutes)"
msgstr ""
+msgid "Maximum duration of a session."
+msgstr ""
+
msgid "Maximum job timeout"
msgstr ""
@@ -11646,12 +11655,24 @@ msgstr ""
msgid "Maximum number of mirrors that can be synchronizing at the same time."
msgstr ""
+msgid "Maximum number of projects."
+msgstr ""
+
msgid "Maximum page reached"
msgstr ""
msgid "Maximum push size (MB)"
msgstr ""
+msgid "Maximum size limit for a single commit."
+msgstr ""
+
+msgid "Maximum size limit for each repository."
+msgstr ""
+
+msgid "Maximum size of individual attachments in comments."
+msgstr ""
+
msgid "Maximum time between updates that a mirror can have when scheduled to synchronize."
msgstr ""
@@ -17024,9 +17045,6 @@ msgstr ""
msgid "Session duration (minutes)"
msgstr ""
-msgid "Session expiration, projects limit and attachment size."
-msgstr ""
-
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -17066,6 +17084,9 @@ msgstr ""
msgid "Set parent epic to an epic"
msgstr ""
+msgid "Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan."
+msgstr ""
+
msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authentication."
msgstr ""
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index 3f3711f9eb8..d3a0c9b790b 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -83,15 +83,15 @@ describe 'User updates wiki page' do
end
it 'updates the commit message as the title is changed', :js do
- fill_in(:wiki_title, with: 'Wiki title')
+ fill_in(:wiki_title, with: '& < > \ \ { } &')
- expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
+ expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &')
end
- it 'does not allow XSS', :js do
- fill_in(:wiki_title, with: '<script>')
+ it 'correctly escapes the commit message entities', :js do
+ fill_in(:wiki_title, with: 'Wiki title')
- expect(page).to have_field('wiki[message]', with: 'Update &lt;script&gt;')
+ expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
end
it 'shows a validation error message' do
diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
index 77e725e7f11..c7856342fb2 100644
--- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
@@ -129,6 +129,18 @@ describe 'User views a wiki page' do
end
end
+ context 'when a page has XSS in its message' do
+ before do
+ wiki_page.update(message: '<script>alert(true)<script>', content: 'XSS update')
+ end
+
+ it 'safely displays the message' do
+ visit(project_wiki_history_path(project, wiki_page))
+
+ expect(page).to have_content('<script>alert(true)<script>')
+ end
+ end
+
context 'when page has invalid content encoding' do
let(:content) { (+'whatever').force_encoding('ISO-8859-1') }
diff --git a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
new file mode 100644
index 00000000000..2b9668c1b56
--- /dev/null
+++ b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
@@ -0,0 +1,94 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Dashboard template matches the default snapshot 1`] = `
+<div
+ class="prometheus-graphs"
+ data-qa-selector="prometheus_graphs"
+>
+ <div
+ class="prometheus-graphs-header gl-p-3 pb-0 border-bottom bg-gray-light"
+ >
+ <div
+ class="row"
+ >
+ <gl-form-group-stub
+ class="col-sm-12 col-md-6 col-lg-2"
+ label="Dashboard"
+ label-for="monitor-dashboards-dropdown"
+ label-size="sm"
+ >
+ <dashboards-dropdown-stub
+ class="mb-0 d-flex"
+ defaultbranch="master"
+ id="monitor-dashboards-dropdown"
+ selecteddashboard="[object Object]"
+ toggle-class="dropdown-menu-toggle"
+ />
+ </gl-form-group-stub>
+
+ <gl-form-group-stub
+ class="col-sm-6 col-md-6 col-lg-2"
+ label="Environment"
+ label-for="monitor-environments-dropdown"
+ label-size="sm"
+ >
+ <gl-dropdown-stub
+ class="mb-0 d-flex"
+ data-qa-selector="environments_dropdown"
+ id="monitor-environments-dropdown"
+ menu-class="monitor-environment-dropdown-menu"
+ text="production"
+ toggle-class="dropdown-menu-toggle"
+ >
+ <div
+ class="d-flex flex-column overflow-hidden"
+ >
+ <gl-dropdown-header-stub
+ class="text-center"
+ >
+ Environment
+ </gl-dropdown-header-stub>
+
+ <gl-dropdown-divider-stub />
+
+ <!---->
+
+ <div
+ class="flex-fill overflow-auto"
+ />
+
+ <!---->
+ </div>
+ </gl-dropdown-stub>
+ </gl-form-group-stub>
+
+ <gl-form-group-stub
+ class="col-sm-6 col-md-6 col-lg-4"
+ label="Show last"
+ label-for="monitor-time-window-dropdown"
+ label-size="sm"
+ >
+ <date-time-picker-stub
+ end="2020-01-01T18:57:47.000Z"
+ start="2020-01-01T18:27:47.000Z"
+ timewindows="[object Object]"
+ />
+ </gl-form-group-stub>
+
+ <!---->
+ </div>
+ </div>
+
+ <empty-state-stub
+ clusterspath="/path/to/clusters"
+ documentationpath="/path/to/docs"
+ emptygettingstartedsvgpath="/path/to/getting-started.svg"
+ emptyloadingsvgpath="/path/to/loading.svg"
+ emptynodatasmallsvgpath="/path/to/no-data-small.svg"
+ emptynodatasvgpath="/path/to/no-data.svg"
+ emptyunabletoconnectsvgpath="/path/to/unable-to-connect.svg"
+ selectedstate="gettingStarted"
+ settingspath="/path/to/settings"
+ />
+</div>
+`;
diff --git a/spec/frontend/monitoring/components/dashboard_template_spec.js b/spec/frontend/monitoring/components/dashboard_template_spec.js
new file mode 100644
index 00000000000..d525f4821f4
--- /dev/null
+++ b/spec/frontend/monitoring/components/dashboard_template_spec.js
@@ -0,0 +1,45 @@
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import Dashboard from '~/monitoring/components/dashboard.vue';
+import { createStore } from '~/monitoring/stores';
+import { propsData } from '../init_utils';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ getParameterValues: jest.fn().mockImplementation(param => {
+ if (param === 'start') return ['2020-01-01T18:27:47.000Z'];
+ if (param === 'end') return ['2020-01-01T18:57:47.000Z'];
+ return [];
+ }),
+}));
+
+describe('Dashboard template', () => {
+ let wrapper;
+ let store;
+ let mock;
+
+ beforeEach(() => {
+ store = createStore();
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ mock.restore();
+ });
+
+ it('matches the default snapshot', () => {
+ wrapper = shallowMount(Dashboard, {
+ propsData: { ...propsData },
+ methods: {
+ fetchData: jest.fn(),
+ },
+ store,
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 6ac7b4af452..e88209081d4 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1340,6 +1340,7 @@ describe API::Projects do
expect(json_response['path']).to be_present
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
+ expect(json_response['can_create_merge_request_in']).to be_present
expect(json_response['wiki_enabled']).to be_present
expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
@@ -1390,6 +1391,7 @@ describe API::Projects do
expect(json_response['path']).to be_present
expect(json_response['issues_enabled']).to be_present
expect(json_response['merge_requests_enabled']).to be_present
+ expect(json_response['can_create_merge_request_in']).to be_present
expect(json_response['wiki_enabled']).to be_present
expect(json_response['jobs_enabled']).to be_present
expect(json_response['snippets_enabled']).to be_present
diff --git a/spec/tasks/gitlab/seed/group_seed_rake_spec.rb b/spec/tasks/gitlab/seed/group_seed_rake_spec.rb
new file mode 100644
index 00000000000..bc217281594
--- /dev/null
+++ b/spec/tasks/gitlab/seed/group_seed_rake_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'rake_helper'
+
+describe 'gitlab:seed:group_seed rake task', :sidekiq do
+ let(:username) { 'group_seed' }
+ let!(:user) { create(:user, username: username) }
+ let(:task_params) { [2, username] }
+
+ before do
+ Rake.application.rake_require('tasks/gitlab/seed/group_seed')
+ end
+
+ subject { run_rake_task('gitlab:seed:group_seed', task_params) }
+
+ it 'performs group seed successfully' do
+ expect { subject }.not_to raise_error
+
+ group = user.groups.first
+
+ expect(user.groups.count).to be 3
+ expect(group.projects.count).to be 2
+ expect(group.members.count).to be 3
+ expect(group.milestones.count).to be 2
+ end
+end