Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
be37a0ee5e
commit
50ae406553
|
|
@ -88,3 +88,4 @@ jsdoc/
|
|||
/qa/.rakeTasks
|
||||
webpack-dev-server.json
|
||||
/.nvimrc
|
||||
.solargraph.yml
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1.14.0
|
||||
1.15.0
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Displays package tags next to the name on the new package list page
|
||||
merge_request: 23675
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add can_create_merge_request_in to /project/:id API response
|
||||
merge_request: 23577
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Auto generated wiki commit message containing HTML encoded entities
|
||||
merge_request: 21371
|
||||
author: 2knal
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add clarifying content to account fields
|
||||
merge_request:
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix custom charts in monitoring dashboard shrinking
|
||||
merge_request: 23649
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update links related to MR approvals in UI
|
||||
merge_request: 23948
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add broadcast types to broadcast messages
|
||||
merge_request:
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Upgrade Pages to 1.15.0
|
||||
merge_request: 24043
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Prevent project path namespace overflow during import
|
||||
merge_request: 24042
|
||||
author: George Tsiolis
|
||||
type: fixed
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 ""
|
||||
|
||||
|
|
|
|||
|
|
@ -83,17 +83,17 @@ describe 'User updates wiki page' do
|
|||
end
|
||||
|
||||
it 'updates the commit message as the title is changed', :js do
|
||||
fill_in(:wiki_title, with: '& < > \ \ { } &')
|
||||
|
||||
expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &')
|
||||
end
|
||||
|
||||
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 Wiki title')
|
||||
end
|
||||
|
||||
it 'does not allow XSS', :js do
|
||||
fill_in(:wiki_title, with: '<script>')
|
||||
|
||||
expect(page).to have_field('wiki[message]', with: 'Update <script>')
|
||||
end
|
||||
|
||||
it 'shows a validation error message' do
|
||||
fill_in(:wiki_content, with: '')
|
||||
click_button('Save changes')
|
||||
|
|
|
|||
|
|
@ -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') }
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
`;
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue