summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-17 09:08:24 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-17 09:08:24 +0000
commit728a207ea6a99a4bddc16dbbe82294d3fdb60fe4 (patch)
tree4bc3b6a859681de3bbeabd7bf2ec5ffd756f3a0a
parentea20020f71c7226d57b6449b1d9b6c6f1298223e (diff)
downloadgitlab-ce-728a207ea6a99a4bddc16dbbe82294d3fdb60fe4.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/boards/components/board.js9
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue3
-rw-r--r--app/assets/javascripts/error_tracking/components/error_details.vue25
-rw-r--r--app/assets/javascripts/error_tracking/queries/details.query.graphql2
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/form.vue5
-rw-r--r--app/controllers/registrations_controller.rb10
-rw-r--r--app/models/user.rb6
-rw-r--r--app/presenters/project_presenter.rb19
-rw-r--r--app/services/users/build_service.rb8
-rw-r--r--app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml10
-rw-r--r--app/views/devise/shared/_signup_box.html.haml2
-rw-r--r--app/views/registrations/welcome.html.haml6
-rw-r--r--app/views/shared/boards/components/_board.html.haml5
-rw-r--r--changelogs/unreleased/197343-iscompact.yml5
-rw-r--r--changelogs/unreleased/36667-add-release-count-to-project-homepage.yml5
-rw-r--r--changelogs/unreleased/37449-fix-eks-authenticate-button.yml5
-rw-r--r--changelogs/unreleased/38223-link-to-gitlab-commit-in-error-detail-page-FE.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-split-signup-full-name.yml5
-rw-r--r--doc/administration/monitoring/gitlab_instance_administration_project/index.md4
-rw-r--r--doc/user/application_security/container_scanning/index.md2
-rw-r--r--doc/user/packages/index.md2
-rw-r--r--doc/user/project/operations/error_tracking.md12
-rw-r--r--doc/user/project/operations/img/error_details_with_issue_v12_7.pngbin0 -> 80625 bytes
-rw-r--r--locale/gitlab.pot58
-rw-r--r--spec/controllers/registrations_controller_spec.rb19
-rw-r--r--spec/features/users/signup_spec.rb134
-rw-r--r--spec/frontend/boards/issue_card_spec.js1
-rw-r--r--spec/frontend/create_cluster/eks_cluster/components/service_credentials_form_spec.js7
-rw-r--r--spec/frontend/cycle_analytics/limit_warning_component_spec.js1
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js32
-rw-r--r--spec/frontend/jobs/components/erased_block_spec.js1
-rw-r--r--spec/frontend/notes/components/discussion_actions_spec.js1
-rw-r--r--spec/frontend/releases/detail/components/app_spec.js1
-rw-r--r--spec/javascripts/ide/components/commit_sidebar/form_spec.js19
-rw-r--r--spec/models/user_spec.rb6
-rw-r--r--spec/presenters/project_presenter_spec.rb250
36 files changed, 493 insertions, 192 deletions
diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js
index 8ebdfede8f7..a6deb656b37 100644
--- a/app/assets/javascripts/boards/components/board.js
+++ b/app/assets/javascripts/boards/components/board.js
@@ -3,7 +3,7 @@ import Sortable from 'sortablejs';
import Vue from 'vue';
import { GlButtonGroup, GlButton, GlTooltip } from '@gitlab/ui';
import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
-import { n__, s__ } from '~/locale';
+import { s__, __, sprintf } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
import AccessorUtilities from '../../lib/utils/accessor';
@@ -67,10 +67,13 @@ export default Vue.extend({
!this.disabled && this.list.type !== ListType.closed && this.list.type !== ListType.blank
);
},
- counterTooltip() {
+ issuesTooltip() {
const { issuesSize } = this.list;
- return `${n__('%d issue', '%d issues', issuesSize)}`;
+
+ return sprintf(__('%{issuesSize} issues'), { issuesSize });
},
+ // Only needed to make karma pass.
+ weightCountToolTip() {}, // eslint-disable-line vue/return-in-computed-property
caretTooltip() {
return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand');
},
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
index 1dd4c468ae6..49a5d4657af 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/service_credentials_form.vue
@@ -82,7 +82,7 @@ export default {
};
</script>
<template>
- <form name="service-credentials-form" @submit.prevent="createRole({ roleArn, externalId })">
+ <form name="service-credentials-form">
<h2>{{ s__('ClusterIntegration|Authenticate with Amazon Web Services') }}</h2>
<p>
{{
@@ -136,6 +136,7 @@ export default {
:disabled="submitButtonDisabled"
:loading="isCreatingRole"
:label="submitButtonLabel"
+ @click.prevent="createRole({ roleArn, externalId })"
/>
</form>
</template>
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue
index 3d3447012db..51a1ae50467 100644
--- a/app/assets/javascripts/error_tracking/components/error_details.vue
+++ b/app/assets/javascripts/error_tracking/components/error_details.vue
@@ -235,18 +235,23 @@ export default {
>{{ error.tags.logger }}
</gl-badge>
</template>
-
- <h3>{{ __('Error details') }}</h3>
<ul>
+ <li v-if="GQLerror.gitlabCommit">
+ <strong class="bold">{{ __('GitLab commit') }}:</strong>
+ <gl-link :href="GQLerror.gitlabCommitPath">
+ <span>{{ GQLerror.gitlabCommit.substr(0, 10) }}</span>
+ </gl-link>
+ </li>
<li v-if="error.gitlab_issue">
- <span class="bold">{{ __('GitLab Issue') }}:</span>
+ <strong class="bold">{{ __('GitLab Issue') }}:</strong>
<gl-link :href="error.gitlab_issue">
<span>{{ error.gitlab_issue }}</span>
</gl-link>
</li>
<li>
- <span class="bold">{{ __('Sentry event') }}:</span>
+ <strong class="bold">{{ __('Sentry event') }}:</strong>
<gl-link
+ class="d-inline-flex align-items-center"
v-track-event="trackClickErrorLinkToSentryOptions(GQLerror.externalUrl)"
:href="GQLerror.externalUrl"
target="_blank"
@@ -256,25 +261,25 @@ export default {
</gl-link>
</li>
<li v-if="GQLerror.firstReleaseShortVersion">
- <span class="bold">{{ __('First seen') }}:</span>
+ <strong class="bold">{{ __('First seen') }}:</strong>
{{ formatDate(GQLerror.firstSeen) }}
<gl-link :href="firstReleaseLink" target="_blank">
- <span>{{ __('Release') }}: {{ GQLerror.firstReleaseShortVersion }}</span>
+ <span>{{ __('Release') }}: {{ GQLerror.firstReleaseShortVersion.substr(0, 10) }}</span>
</gl-link>
</li>
<li v-if="GQLerror.lastReleaseShortVersion">
- <span class="bold">{{ __('Last seen') }}:</span>
+ <strong class="bold">{{ __('Last seen') }}:</strong>
{{ formatDate(GQLerror.lastSeen) }}
<gl-link :href="lastReleaseLink" target="_blank">
- <span>{{ __('Release') }}: {{ GQLerror.lastReleaseShortVersion }}</span>
+ <span>{{ __('Release') }}: {{ GQLerror.lastReleaseShortVersion.substr(0, 10) }}</span>
</gl-link>
</li>
<li>
- <span class="bold">{{ __('Events') }}:</span>
+ <strong class="bold">{{ __('Events') }}:</strong>
<span>{{ GQLerror.count }}</span>
</li>
<li>
- <span class="bold">{{ __('Users') }}:</span>
+ <strong class="bold">{{ __('Users') }}:</strong>
<span>{{ GQLerror.userCount }}</span>
</li>
</ul>
diff --git a/app/assets/javascripts/error_tracking/queries/details.query.graphql b/app/assets/javascripts/error_tracking/queries/details.query.graphql
index f65bdb9b968..625ce3030d9 100644
--- a/app/assets/javascripts/error_tracking/queries/details.query.graphql
+++ b/app/assets/javascripts/error_tracking/queries/details.query.graphql
@@ -13,6 +13,8 @@ query errorDetails($fullPath: ID!, $errorId: ID!) {
externalUrl
firstReleaseShortVersion
lastReleaseShortVersion
+ gitlabCommit
+ gitlabCommitPath
}
}
}
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
index 002c00599bb..9d5473a1201 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
@@ -60,6 +60,11 @@ export default {
);
}
},
+
+ lastCommitMsg() {
+ this.isCompact =
+ this.currentActivityView !== activityBarViews.commit && this.lastCommitMsg === '';
+ },
},
methods: {
...mapActions(['updateActivityBarView']),
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 5fc7f5c84f0..c0ba87bf3ed 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -60,7 +60,7 @@ class RegistrationsController < Devise::RegistrationsController
end
def update_registration
- user_params = params.require(:user).permit(:name, :role, :setup_for_company)
+ user_params = params.require(:user).permit(:role, :setup_for_company)
result = ::Users::SignupService.new(current_user, user_params).execute
if result[:status] == :success
@@ -152,13 +152,7 @@ class RegistrationsController < Devise::RegistrationsController
end
def sign_up_params
- clean_params = params.require(:user).permit(:username, :email, :email_confirmation, :name, :password)
-
- if experiment_enabled?(:signup_flow)
- clean_params[:name] = clean_params[:username]
- end
-
- clean_params
+ params.require(:user).permit(:username, :email, :email_confirmation, :name, :first_name, :last_name, :password)
end
def resource_name
diff --git a/app/models/user.rb b/app/models/user.rb
index 4bba4d47b8f..df54f358ffa 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -164,9 +164,9 @@ class User < ApplicationRecord
# Validations
#
# Note: devise :validatable above adds validations for :email and :password
- validates :name, presence: true, length: { maximum: 128 }
- validates :first_name, length: { maximum: 255 }
- validates :last_name, length: { maximum: 255 }
+ validates :name, presence: true, length: { maximum: 255 }
+ validates :first_name, length: { maximum: 127 }
+ validates :last_name, length: { maximum: 127 }
validates :email, confirmation: true
validates :notification_email, presence: true
validates :notification_email, devise_email: true, if: ->(user) { user.notification_email != user.email }
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 45f4668112b..8c24d07675a 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -24,7 +24,8 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
- files_anchor_data
+ files_anchor_data,
+ releases_anchor_data
].compact.select(&:is_link)
end
@@ -153,6 +154,22 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
empty_repo? ? nil : project_tree_path(project))
end
+ def releases_anchor_data
+ return unless can?(current_user, :read_release, project)
+
+ releases_count = project.releases.count
+ return if releases_count < 1
+
+ AnchorData.new(true,
+ statistic_icon('rocket') +
+ n_('%{strong_start}%{release_count}%{strong_end} Release', '%{strong_start}%{release_count}%{strong_end} Releases', releases_count).html_safe % {
+ release_count: number_with_delimiter(releases_count),
+ strong_start: '<strong class="project-stat-value">'.html_safe,
+ strong_end: '</strong>'.html_safe
+ },
+ project_releases_path(project))
+ end
+
def commits_anchor_data
AnchorData.new(true,
statistic_icon('commit') +
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index ea4d11e728e..d18f20bc1db 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -86,6 +86,8 @@ module Users
:email_confirmation,
:password_automatically_set,
:name,
+ :first_name,
+ :last_name,
:password,
:username
]
@@ -107,6 +109,12 @@ module Users
if user_params[:skip_confirmation].nil?
user_params[:skip_confirmation] = skip_user_confirmation_email_from_setting
end
+
+ fallback_name = "#{user_params[:first_name]} #{user_params[:last_name]}"
+
+ if user_params[:name].blank? && fallback_name.present?
+ user_params = user_params.merge(name: fallback_name)
+ end
end
if user_default_internal_regex_enabled? && !user_params.key?(:external)
diff --git a/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
index e3142ff96a1..4832861445b 100644
--- a/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
+++ b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
@@ -1,4 +1,5 @@
- content_for(:page_title, _('Register for GitLab'))
+- max_first_name_length = max_last_name_length = 127
- max_username_length = 255
.signup-box.p-3.mb-2
.signup-body
@@ -7,9 +8,16 @@
= render "devise/shared/error_messages", resource: resource
- if Feature.enabled?(:invisible_captcha)
= invisible_captcha
+ .name.form-row
+ .col.form-group
+ = f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
+ = f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First Name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_firstname_field' }, required: true, title: _("This field is required.")
+ .col.form-group
+ = f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
+ = f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last Name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_lastname_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
- = f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
+ = f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :max_length => max_username_length, :max_length_message => _("Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
%p.validation-error.gl-field-error-ignore.field-validation.mt-1.hide.cred= _('Username is already taken.')
%p.validation-success.gl-field-error-ignore.field-validation.mt-1.hide.cgreen= _('Username is available.')
%p.validation-pending.gl-field-error-ignore.field-validation.mt-1.hide= _('Checking username availability...')
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index 2cd77af6877..7c5b85c903c 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -1,4 +1,4 @@
-- max_name_length = 128
+- max_name_length = 255
- max_username_length = 255
#register-pane.tab-pane.login-box{ role: 'tabpanel' }
.login-body
diff --git a/app/views/registrations/welcome.html.haml b/app/views/registrations/welcome.html.haml
index 7b92f5070df..bc8d7ed10ef 100644
--- a/app/views/registrations/welcome.html.haml
+++ b/app/views/registrations/welcome.html.haml
@@ -1,5 +1,4 @@
-- content_for(:page_title, _('Welcome to GitLab @%{username}!') % { username: current_user.username })
-- max_name_length = 128
+- content_for(:page_title, _('Welcome to GitLab %{name}!') % { name: current_user.name })
.text-center.mb-3
= _('In order to tailor your experience with GitLab we<br>would like to know a bit more about you.').html_safe
.signup-box.p-3.mb-2
@@ -7,9 +6,6 @@
= form_for(current_user, url: users_sign_up_update_registration_path, html: { class: 'new_new_user gl-show-field-errors', 'aria-live' => 'assertive' }) do |f|
.devise-errors.mt-0
= render 'devise/shared/error_messages', resource: current_user
- .name.form-group
- = f.label :name, _('Full name'), class: 'label-bold'
- = f.text_field :name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_name_length, :max_length_message => s_('Name is too long (maximum is %{max_length} characters).') % { max_length: max_name_length }, :qa_selector => 'new_user_name_field' }, required: true, title: _('This field is required.')
.form-group
= f.label :role, _('Role'), class: 'label-bold'
= f.select :role, ::User.roles.keys.map { |role| [role.titleize, role] }, {}, class: 'form-control'
diff --git a/app/views/shared/boards/components/_board.html.haml b/app/views/shared/boards/components/_board.html.haml
index eb9b7f6c48a..a62c385d711 100644
--- a/app/views/shared/boards/components/_board.html.haml
+++ b/app/views/shared/boards/components/_board.html.haml
@@ -42,9 +42,10 @@
%button.board-delete.no-drag.p-0.border-0.has-tooltip.float-right{ type: "button", title: _("Delete list"), ":class": "{ 'd-none': !list.isExpanded }", "aria-label" => _("Delete list"), data: { placement: "bottom" }, "@click.stop" => "deleteBoard" }
= icon("trash")
- .issue-count-badge.pr-0.no-drag.text-secondary{ "v-if" => "showBoardListAndBoardInfo", ":title": "counterTooltip", "v-tooltip": true, data: { placement: "top" } }
+ .issue-count-badge.pr-0.no-drag.text-secondary{ "v-if" => "showBoardListAndBoardInfo" }
%span.d-inline-flex
- %span.issue-count-badge-count
+ %gl-tooltip{ ":target" => "() => $refs.issueCount", ":title" => "issuesTooltip" }
+ %span.issue-count-badge-count{ "ref" => "issueCount" }
%icon.mr-1{ name: "issues" }
%issue-count{ ":maxIssueCount" => "list.maxIssueCount",
":issuesSize" => "list.issuesSize" }
diff --git a/changelogs/unreleased/197343-iscompact.yml b/changelogs/unreleased/197343-iscompact.yml
new file mode 100644
index 00000000000..d85e729d2bd
--- /dev/null
+++ b/changelogs/unreleased/197343-iscompact.yml
@@ -0,0 +1,5 @@
+---
+title: Fix unexpected behaviour of the commit form after committing in Web IDE
+merge_request: 23238
+author:
+type: fixed
diff --git a/changelogs/unreleased/36667-add-release-count-to-project-homepage.yml b/changelogs/unreleased/36667-add-release-count-to-project-homepage.yml
new file mode 100644
index 00000000000..3a8e26b0087
--- /dev/null
+++ b/changelogs/unreleased/36667-add-release-count-to-project-homepage.yml
@@ -0,0 +1,5 @@
+---
+title: Add release count to project homepage
+merge_request: 21350
+author:
+type: added
diff --git a/changelogs/unreleased/37449-fix-eks-authenticate-button.yml b/changelogs/unreleased/37449-fix-eks-authenticate-button.yml
new file mode 100644
index 00000000000..e0871e7d7c6
--- /dev/null
+++ b/changelogs/unreleased/37449-fix-eks-authenticate-button.yml
@@ -0,0 +1,5 @@
+---
+title: 'fix: EKS credentials form does not reset after error'
+merge_request: 21958
+author:
+type: other
diff --git a/changelogs/unreleased/38223-link-to-gitlab-commit-in-error-detail-page-FE.yml b/changelogs/unreleased/38223-link-to-gitlab-commit-in-error-detail-page-FE.yml
new file mode 100644
index 00000000000..8adae3d266d
--- /dev/null
+++ b/changelogs/unreleased/38223-link-to-gitlab-commit-in-error-detail-page-FE.yml
@@ -0,0 +1,5 @@
+---
+title: Link to GitLab commit in Sentry error details page
+merge_request: 22431
+author:
+type: added
diff --git a/changelogs/unreleased/nicolasdular-split-signup-full-name.yml b/changelogs/unreleased/nicolasdular-split-signup-full-name.yml
new file mode 100644
index 00000000000..08c45cb22ba
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-split-signup-full-name.yml
@@ -0,0 +1,5 @@
+---
+title: Update name max length
+merge_request: 22840
+author:
+type: changed
diff --git a/doc/administration/monitoring/gitlab_instance_administration_project/index.md b/doc/administration/monitoring/gitlab_instance_administration_project/index.md
index b07bbafaf7d..8675521ddb1 100644
--- a/doc/administration/monitoring/gitlab_instance_administration_project/index.md
+++ b/doc/administration/monitoring/gitlab_instance_administration_project/index.md
@@ -1,7 +1,9 @@
# GitLab instance administration project
NOTE: **Note:**
-This feature is not yet available and is [planned for 12.6](https://gitlab.com/gitlab-org/gitlab/issues/32351).
+This feature is available behind a feature flag called `self_monitoring_project`
+since [12.7](https://gitlab.com/gitlab-org/gitlab/issues/32351). The feature flag
+will be removed once we [add dashboards to display metrics](https://gitlab.com/groups/gitlab-org/-/epics/2367).
GitLab has been adding the ability for administrators to see insights into the health of
their GitLab instance. In order to surface this experience in a native way, similar to how
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index eb726ee2ed7..de8854bda0a 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -305,7 +305,7 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `vulnerabilities[].location.dependency.package.name` | Name of the package where the vulnerability is located. |
| `vulnerabilities[].location.dependency.version` | Version of the vulnerable package. Optional. |
| `vulnerabilities[].location.operating_system` | The operating system that contains the vulnerable package. |
-| `vulnerabilities[].location.image` | The Docker image that was analyzed. Optional. |
+| `vulnerabilities[].location.image` | The Docker image that was analyzed. |
| `vulnerabilities[].identifiers` | An ordered array of references that identify a vulnerability on internal or external DBs. |
| `vulnerabilities[].identifiers[].type` | Type of the identifier. Possible values: common identifier types (among `cve`, `cwe`, `osvdb`, and `usn`). |
| `vulnerabilities[].identifiers[].name` | Name of the identifier for display purpose. |
diff --git a/doc/user/packages/index.md b/doc/user/packages/index.md
index 594be1757c1..c58effac59d 100644
--- a/doc/user/packages/index.md
+++ b/doc/user/packages/index.md
@@ -13,7 +13,7 @@ The Packages feature allows GitLab to act as a repository for the following:
| [Conan Repository](conan_repository/index.md) **(PREMIUM)** | The GitLab Conan Repository enables every project in GitLab to have its own space to store [Conan](https://conan.io/) packages. | 12.6+ |
| [Maven Repository](maven_repository/index.md) **(PREMIUM)** | The GitLab Maven Repository enables every project in GitLab to have its own space to store [Maven](https://maven.apache.org/) packages. | 11.3+ |
| [NPM Registry](npm_registry/index.md) **(PREMIUM)** | The GitLab NPM Registry enables every project in GitLab to have its own space to store [NPM](https://www.npmjs.com/) packages. | 11.7+ |
-| [NuGet Repository](nuget_repository/index.md) **(PREMIUM)** | *COMING SOON* The GitLab NuGet Repository will enable every project in GitLab to have its own space to store [NuGet](https://www.nuget.org/) packages. | 12.8+ |
+| [NuGet Repository](nuget_repository/index.md) **(PREMIUM)** | *PLANNED* The GitLab NuGet Repository will enable every project in GitLab to have its own space to store [NuGet](https://www.nuget.org/) packages. | 12.8+ |
TIP: **Tip:**
Don't you see your package management system supported yet? Consider contributing
diff --git a/doc/user/project/operations/error_tracking.md b/doc/user/project/operations/error_tracking.md
index 5246f8072e2..f76c9d9912b 100644
--- a/doc/user/project/operations/error_tracking.md
+++ b/doc/user/project/operations/error_tracking.md
@@ -55,13 +55,13 @@ This page has:
- A link to the Sentry issue.
- Other details about the issue, including a full stack trace.
-If the error has not been linked to an existing GitLab issue, a 'Create Issue' button will be visible:
+If the error has not been linked to an existing GitLab issue, a 'Create issue' button will be visible:
![Error Details without Issue Link](img/error_details_v12_6.png)
-If a link does exist, it will be shown in the details and the 'Create Issue' button will be hidden:
+If a link does exist, it will be shown in the details and the 'Create issue' button will change to a 'View issue' button:
-![Error Details with Issue Link](img/error_details_with_issue_v12_6.png)
+![Error Details with Issue Link](img/error_details_with_issue_v12_7.png)
## Taking Action on errors
@@ -74,3 +74,9 @@ You can take action on Sentry Errors from within the GitLab UI.
From within the [Error Details](#error-details) page you can ignore a Sentry error by simply clicking the **Ignore** button near the top of the page.
Ignoring an error will prevent it from appearing in the [Error Tracking List](#error-tracking-list), and will silence notifications that were set up within Sentry.
+
+### Resolving errors
+
+From within the [Error Details](#error-details) page you can resolve a Sentry error by simply clicking the **Resolve** button near the top of the page.
+
+Marking an error as resolved indicates that the error has stopped firing events. If another event occurs, the error reverts to unresolved.
diff --git a/doc/user/project/operations/img/error_details_with_issue_v12_7.png b/doc/user/project/operations/img/error_details_with_issue_v12_7.png
new file mode 100644
index 00000000000..aa846ee7220
--- /dev/null
+++ b/doc/user/project/operations/img/error_details_with_issue_v12_7.png
Binary files differ
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e1770da3e99..5f1f9c0d49f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -284,6 +284,12 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
+msgid "%{issuesSize} issues"
+msgstr ""
+
+msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgstr ""
+
msgid "%{label_for_message} unavailable"
msgstr ""
@@ -401,6 +407,11 @@ msgstr[1] ""
msgid "%{strong_start}%{human_size}%{strong_end} Files"
msgstr ""
+msgid "%{strong_start}%{release_count}%{strong_end} Release"
+msgid_plural "%{strong_start}%{release_count}%{strong_end} Releases"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{strong_start}%{tag_count}%{strong_end} Tag"
msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
msgstr[0] ""
@@ -435,6 +446,9 @@ msgstr ""
msgid "%{title} changes"
msgstr ""
+msgid "%{totalWeight} total weight"
+msgstr ""
+
msgid "%{total} open issue weight"
msgstr ""
@@ -3299,9 +3313,21 @@ msgstr ""
msgid "Checkout"
msgstr ""
+msgid "Checkout|$%{selectedPlanPrice} per user per year"
+msgstr ""
+
+msgid "Checkout|%{name}'s GitLab subscription"
+msgstr ""
+
msgid "Checkout|%{selectedPlanText} plan"
msgstr ""
+msgid "Checkout|%{startDate} - %{endDate}"
+msgstr ""
+
+msgid "Checkout|(x%{numberOfUsers})"
+msgstr ""
+
msgid "Checkout|1. Your profile"
msgstr ""
@@ -3338,9 +3364,21 @@ msgstr ""
msgid "Checkout|Subscription details"
msgstr ""
+msgid "Checkout|Subtotal"
+msgstr ""
+
+msgid "Checkout|Tax"
+msgstr ""
+
+msgid "Checkout|Total"
+msgstr ""
+
msgid "Checkout|Users"
msgstr ""
+msgid "Checkout|Your organization"
+msgstr ""
+
msgid "Checkout|company or team"
msgstr ""
@@ -7275,9 +7313,6 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
-msgid "Error details"
-msgstr ""
-
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -8139,6 +8174,9 @@ msgstr ""
msgid "Finished"
msgstr ""
+msgid "First Name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
msgid "First Seen"
msgstr ""
@@ -8838,6 +8876,9 @@ msgstr ""
msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
msgstr ""
+msgid "GitLab commit"
+msgstr ""
+
msgid "GitLab for Slack"
msgstr ""
@@ -10668,6 +10709,9 @@ msgstr ""
msgid "Last Accessed On"
msgstr ""
+msgid "Last Name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
msgid "Last Pipeline"
msgstr ""
@@ -11991,9 +12035,6 @@ msgstr ""
msgid "Name has already been taken"
msgstr ""
-msgid "Name is too long (maximum is %{max_length} characters)."
-msgstr ""
-
msgid "Name new label"
msgstr ""
@@ -20461,6 +20502,9 @@ msgstr ""
msgid "Username is available."
msgstr ""
+msgid "Username is too long (maximum is %{max_length} characters)."
+msgstr ""
+
msgid "Username or email"
msgstr ""
@@ -20835,7 +20879,7 @@ msgstr ""
msgid "Welcome to GitLab"
msgstr ""
-msgid "Welcome to GitLab @%{username}!"
+msgid "Welcome to GitLab %{name}!"
msgstr ""
msgid "Welcome to the Guided GitLab Tour"
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index da36148ba85..214eb35ec9d 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -306,6 +306,23 @@ describe RegistrationsController do
expect(subject.current_user).not_to be_nil
end
+
+ context 'with the experimental signup flow enabled and the user is part of the experimental group' do
+ before do
+ stub_experiment(signup_flow: true)
+ stub_experiment_for_user(signup_flow: true)
+ end
+
+ let(:base_user_params) { { first_name: 'First', last_name: 'Last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
+
+ it 'sets name from first and last name' do
+ post :create, params: { new_user: base_user_params }
+
+ expect(User.last.first_name).to eq(base_user_params[:first_name])
+ expect(User.last.last_name).to eq(base_user_params[:last_name])
+ expect(User.last.name).to eq("#{base_user_params[:first_name]} #{base_user_params[:last_name]}")
+ end
+ end
end
describe '#destroy' do
@@ -395,7 +412,7 @@ describe RegistrationsController do
label: anything,
property: 'experimental_group'
)
- patch :update_registration, params: { user: { name: 'New name', role: 'software_developer', setup_for_company: 'false' } }
+ patch :update_registration, params: { user: { role: 'software_developer', setup_for_company: 'false' } }
end
end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 3b19bd423a4..30f298b1fc3 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -123,50 +123,6 @@ shared_examples 'Signup' do
end
end
- describe 'user\'s full name validation', :js do
- before do
- if Gitlab::Experimentation.enabled?(:signup_flow)
- user = create(:user, role: nil)
- sign_in(user)
- visit users_sign_up_welcome_path
- @user_name_field = 'user_name'
- else
- visit new_user_registration_path
- @user_name_field = 'new_user_name'
- end
- end
-
- it 'does not show an error border if the user\'s fullname length is not longer than 128 characters' do
- fill_in @user_name_field, with: 'u' * 128
-
- expect(find('.name')).not_to have_css '.gl-field-error-outline'
- end
-
- it 'shows an error border if the user\'s fullname contains an emoji' do
- simulate_input("##{@user_name_field}", 'Ehsan 🦋')
-
- expect(find('.name')).to have_css '.gl-field-error-outline'
- end
-
- it 'shows an error border if the user\'s fullname is longer than 128 characters' do
- fill_in @user_name_field, with: 'n' * 129
-
- expect(find('.name')).to have_css '.gl-field-error-outline'
- end
-
- it 'shows an error message if the user\'s fullname is longer than 128 characters' do
- fill_in @user_name_field, with: 'n' * 129
-
- expect(page).to have_content("Name is too long (maximum is 128 characters).")
- end
-
- it 'shows an error message if the username contains emojis' do
- simulate_input("##{@user_name_field}", 'Ehsan 🦋')
-
- expect(page).to have_content("Invalid input, please avoid emojis")
- end
- end
-
context 'with no errors' do
context 'when sending confirmation email' do
before do
@@ -184,7 +140,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -209,7 +168,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -235,7 +197,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email.capitalize
end
@@ -263,7 +228,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -287,7 +255,10 @@ shared_examples 'Signup' do
visit new_user_registration_path
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
end
@@ -313,7 +284,10 @@ shared_examples 'Signup' do
visit new_user_registration_path
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
end
@@ -338,7 +312,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -357,7 +334,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -394,7 +374,10 @@ shared_examples 'Signup' do
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
- unless Gitlab::Experimentation.enabled?(:signup_flow)
+ if Gitlab::Experimentation.enabled?(:signup_flow)
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ else
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_email_confirmation', with: new_user.email
end
@@ -412,6 +395,44 @@ shared_examples 'Signup' do
end
end
+shared_examples 'Signup name validation' do |field, max_length|
+ before do
+ visit new_user_registration_path
+ end
+
+ describe "#{field} validation", :js do
+ it "does not show an error border if the user's fullname length is not longer than #{max_length} characters" do
+ fill_in field, with: 'u' * max_length
+
+ expect(find('.name')).not_to have_css '.gl-field-error-outline'
+ end
+
+ it 'shows an error border if the user\'s fullname contains an emoji' do
+ simulate_input("##{field}", 'Ehsan 🦋')
+
+ expect(find('.name')).to have_css '.gl-field-error-outline'
+ end
+
+ it "shows an error border if the user\'s fullname is longer than #{max_length} characters" do
+ fill_in field, with: 'n' * (max_length + 1)
+
+ expect(find('.name')).to have_css '.gl-field-error-outline'
+ end
+
+ it "shows an error message if the user\'s fullname is longer than #{max_length} characters" do
+ fill_in field, with: 'n' * (max_length + 1)
+
+ expect(page).to have_content("Name is too long (maximum is #{max_length} characters).")
+ end
+
+ it 'shows an error message if the username contains emojis' do
+ simulate_input("##{field}", 'Ehsan 🦋')
+
+ expect(page).to have_content("Invalid input, please avoid emojis")
+ end
+ end
+end
+
describe 'With original flow' do
before do
stub_experiment(signup_flow: false)
@@ -419,6 +440,7 @@ describe 'With original flow' do
end
it_behaves_like 'Signup'
+ it_behaves_like 'Signup name validation', 'new_user_name', 255
end
describe 'With experimental flow' do
@@ -428,11 +450,15 @@ describe 'With experimental flow' do
end
it_behaves_like 'Signup'
+ it_behaves_like 'Signup name validation', 'new_user_first_name', 127
+ it_behaves_like 'Signup name validation', 'new_user_last_name', 127
describe 'when role is required' do
it 'after registering, it redirects to step 2 of the signup process, sets the name and role and then redirects to the original requested url' do
new_user = build_stubbed(:user)
visit new_user_registration_path
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_password', with: new_user.password
@@ -441,13 +467,11 @@ describe 'With experimental flow' do
expect(page).to have_current_path(users_sign_up_welcome_path)
- fill_in 'user_name', with: 'New name'
select 'Software Developer', from: 'user_role'
choose 'user_setup_for_company_true'
click_button 'Get started!'
new_user = User.find_by_username(new_user.username)
- expect(new_user.name).to eq 'New name'
expect(new_user.software_developer_role?).to be_truthy
expect(new_user.setup_for_company).to be_truthy
expect(page).to have_current_path(new_project_path)
diff --git a/spec/frontend/boards/issue_card_spec.js b/spec/frontend/boards/issue_card_spec.js
index b9a88324763..df55a106945 100644
--- a/spec/frontend/boards/issue_card_spec.js
+++ b/spec/frontend/boards/issue_card_spec.js
@@ -50,7 +50,6 @@ describe('Issue card component', () => {
rootPath: '/',
},
store,
- attachToDocument: true,
});
});
diff --git a/spec/frontend/create_cluster/eks_cluster/components/service_credentials_form_spec.js b/spec/frontend/create_cluster/eks_cluster/components/service_credentials_form_spec.js
index 92a5f5116ac..c58638f5c80 100644
--- a/spec/frontend/create_cluster/eks_cluster/components/service_credentials_form_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/components/service_credentials_form_spec.js
@@ -47,7 +47,6 @@ describe('ServiceCredentialsForm', () => {
const findCopyExternalIdButton = () => vm.find('.js-copy-external-id-button');
const findInvalidCredentials = () => vm.find('.js-invalid-credentials');
const findSubmitButton = () => vm.find(LoadingButton);
- const findForm = () => vm.find('form[name="service-credentials-form"]');
it('displays provided account id', () => {
expect(findAccountIdInput().attributes('value')).toBe(accountId);
@@ -77,8 +76,10 @@ describe('ServiceCredentialsForm', () => {
});
});
- it('dispatches createRole action when form is submitted', () => {
- findForm().trigger('submit');
+ it('dispatches createRole action when submit button is clicked', () => {
+ vm.setData({ roleArn: '123' }); // set role ARN to enable button
+
+ findSubmitButton().vm.$emit('click', new Event('click'));
expect(createRoleAction).toHaveBeenCalled();
});
diff --git a/spec/frontend/cycle_analytics/limit_warning_component_spec.js b/spec/frontend/cycle_analytics/limit_warning_component_spec.js
index a4606099b06..e712dea67cb 100644
--- a/spec/frontend/cycle_analytics/limit_warning_component_spec.js
+++ b/spec/frontend/cycle_analytics/limit_warning_component_spec.js
@@ -10,7 +10,6 @@ const createComponent = props =>
propsData: {
...props,
},
- attachToDocument: true,
});
describe('Limit warning component', () => {
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index e876a6da922..e19cb1fd3c1 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -246,5 +246,37 @@ describe('ErrorDetails', () => {
});
});
});
+
+ describe('GitLab commit link', () => {
+ const gitlabCommit = '7975be0116940bf2ad4321f79d02a55c5f7779aa';
+ const gitlabCommitPath =
+ '/gitlab-org/gitlab-test/commit/7975be0116940bf2ad4321f79d02a55c5f7779aa';
+ const findGitLabCommitLink = () => wrapper.find(`[href$="${gitlabCommitPath}"]`);
+
+ it('should display a link', () => {
+ mocks.$apollo.queries.GQLerror.loading = false;
+ wrapper.setData({
+ GQLerror: {
+ gitlabCommit,
+ gitlabCommitPath,
+ },
+ });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findGitLabCommitLink().exists()).toBe(true);
+ });
+ });
+
+ it('should display a link', () => {
+ mocks.$apollo.queries.GQLerror.loading = false;
+ wrapper.setData({
+ GQLerror: {
+ gitlabCommit: null,
+ },
+ });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findGitLabCommitLink().exists()).toBe(false);
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/jobs/components/erased_block_spec.js b/spec/frontend/jobs/components/erased_block_spec.js
index 29a7676abe5..d66ee71df6a 100644
--- a/spec/frontend/jobs/components/erased_block_spec.js
+++ b/spec/frontend/jobs/components/erased_block_spec.js
@@ -13,7 +13,6 @@ describe('Erased block', () => {
const createComponent = props => {
wrapper = mount(ErasedBlock, {
propsData: props,
- attachToDocument: true,
});
};
diff --git a/spec/frontend/notes/components/discussion_actions_spec.js b/spec/frontend/notes/components/discussion_actions_spec.js
index 7e30e166d65..2d95a86d8a6 100644
--- a/spec/frontend/notes/components/discussion_actions_spec.js
+++ b/spec/frontend/notes/components/discussion_actions_spec.js
@@ -35,7 +35,6 @@ describe('DiscussionActions', () => {
shouldShowJumpToNextDiscussion: true,
...props,
},
- attachToDocument: true,
});
};
diff --git a/spec/frontend/releases/detail/components/app_spec.js b/spec/frontend/releases/detail/components/app_spec.js
index 09f348018f4..fd5239ad44e 100644
--- a/spec/frontend/releases/detail/components/app_spec.js
+++ b/spec/frontend/releases/detail/components/app_spec.js
@@ -31,7 +31,6 @@ describe('Release detail component', () => {
wrapper = mount(ReleaseDetailApp, {
store,
- attachToDocument: true,
});
return wrapper.vm.$nextTick();
diff --git a/spec/javascripts/ide/components/commit_sidebar/form_spec.js b/spec/javascripts/ide/components/commit_sidebar/form_spec.js
index 2ee0b94582c..e984389bd46 100644
--- a/spec/javascripts/ide/components/commit_sidebar/form_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/form_spec.js
@@ -76,6 +76,25 @@ describe('IDE commit form', () => {
done();
});
});
+
+ it('collapses if lastCommitMsg is set to empty and current view is not commit view', done => {
+ store.state.lastCommitMsg = 'abc';
+ store.state.currentActivityView = activityBarViews.edit;
+
+ vm.$nextTick(() => {
+ // if commit message is set, form is uncollapsed
+ expect(vm.isCompact).toBe(false);
+
+ store.state.lastCommitMsg = '';
+
+ vm.$nextTick(() => {
+ // collapsed when set to empty
+ expect(vm.isCompact).toBe(true);
+
+ done();
+ });
+ });
+ });
});
describe('full', () => {
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 110f7a5af65..5620f211d9c 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -147,15 +147,15 @@ describe User, :do_not_mock_admin_mode do
describe 'name' do
it { is_expected.to validate_presence_of(:name) }
- it { is_expected.to validate_length_of(:name).is_at_most(128) }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
end
describe 'first name' do
- it { is_expected.to validate_length_of(:first_name).is_at_most(255) }
+ it { is_expected.to validate_length_of(:first_name).is_at_most(127) }
end
describe 'last name' do
- it { is_expected.to validate_length_of(:last_name).is_at_most(255) }
+ it { is_expected.to validate_length_of(:last_name).is_at_most(127) }
end
describe 'username' do
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
index 09ca106c54c..620ef3ff21a 100644
--- a/spec/presenters/project_presenter_spec.rb
+++ b/spec/presenters/project_presenter_spec.rb
@@ -33,10 +33,10 @@ describe ProjectPresenter do
describe '#default_view' do
context 'user not signed in' do
- let(:user) { nil }
+ let_it_be(:user) { nil }
context 'when repository is empty' do
- let(:project) { create(:project_empty_repo, :public) }
+ let_it_be(:project) { create(:project_empty_repo, :public) }
it 'returns activity if user has repository access' do
allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(true)
@@ -52,7 +52,8 @@ describe ProjectPresenter do
end
context 'when repository is not empty' do
- let(:project) { create(:project, :public, :repository) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:release) { create(:release, project: project, author: user) }
it 'returns files and readme if user has repository access' do
allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(true)
@@ -65,6 +66,15 @@ describe ProjectPresenter do
expect(presenter.default_view).to eq('activity')
end
+
+ it 'returns releases anchor' do
+ expect(release).to be_truthy
+ expect(presenter.releases_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including("#{project.releases.count}"),
+ link: presenter.project_releases_path(project)
+ )
+ end
end
end
@@ -121,10 +131,8 @@ describe ProjectPresenter do
end
describe '#can_current_user_push_code?' do
- let(:project) { create(:project, :repository) }
-
context 'empty repo' do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
it 'returns true if user can push_code' do
project.add_developer(user)
@@ -150,6 +158,7 @@ describe ProjectPresenter do
it 'returns false if default branch is protected' do
project.add_developer(user)
+
create(:protected_branch, project: project, name: project.default_branch)
expect(presenter.can_current_user_push_code?).to be(false)
@@ -158,73 +167,125 @@ describe ProjectPresenter do
end
context 'statistics anchors (empty repo)' do
- let(:project) { create(:project, :empty_repo) }
+ let_it_be(:project) { create(:project, :empty_repo) }
describe '#files_anchor_data' do
it 'returns files data' do
- expect(presenter.files_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0 Bytes'),
- link: nil)
+ expect(presenter.files_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0 Bytes'),
+ link: nil
+ )
+ end
+ end
+
+ describe '#releases_anchor_data' do
+ it 'does not return release count' do
+ expect(presenter.releases_anchor_data).to be_nil
end
end
describe '#commits_anchor_data' do
it 'returns commits data' do
- expect(presenter.commits_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0'),
- link: nil)
+ expect(presenter.commits_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0'),
+ link: nil
+ )
end
end
describe '#branches_anchor_data' do
it 'returns branches data' do
- expect(presenter.branches_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0'),
- link: nil)
+ expect(presenter.branches_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0'),
+ link: nil
+ )
end
end
describe '#tags_anchor_data' do
it 'returns tags data' do
- expect(presenter.tags_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0'),
- link: nil)
+ expect(presenter.tags_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0'),
+ link: nil
+ )
end
end
end
context 'statistics anchors' do
- let(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:release) { create(:release, project: project, author: user) }
+ let(:presenter) { described_class.new(project, current_user: user) }
describe '#files_anchor_data' do
it 'returns files data' do
- expect(presenter.files_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0 Bytes'),
- link: presenter.project_tree_path(project))
+ expect(presenter.files_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0 Bytes'),
+ link: presenter.project_tree_path(project)
+ )
+ end
+ end
+
+ describe '#releases_anchor_data' do
+ it 'returns release count if user can read release' do
+ project.add_maintainer(user)
+
+ expect(release).to be_truthy
+ expect(presenter.releases_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including("#{project.releases.count}"),
+ link: presenter.project_releases_path(project)
+ )
+ end
+
+ it 'returns nil if user cannot read release' do
+ expect(release).to be_truthy
+ expect(presenter.releases_anchor_data).to be_nil
+ end
+
+ context 'user not signed in' do
+ let_it_be(:user) { nil }
+
+ it 'returns nil if user is signed out' do
+ expect(release).to be_truthy
+ expect(presenter.releases_anchor_data).to be_nil
+ end
end
end
describe '#commits_anchor_data' do
it 'returns commits data' do
- expect(presenter.commits_anchor_data).to have_attributes(is_link: true,
- label: a_string_including('0'),
- link: presenter.project_commits_path(project, project.repository.root_ref))
+ expect(presenter.commits_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including('0'),
+ link: presenter.project_commits_path(project, project.repository.root_ref)
+ )
end
end
describe '#branches_anchor_data' do
it 'returns branches data' do
- expect(presenter.branches_anchor_data).to have_attributes(is_link: true,
- label: a_string_including("#{project.repository.branches.size}"),
- link: presenter.project_branches_path(project))
+ expect(presenter.branches_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including("#{project.repository.branches.size}"),
+ link: presenter.project_branches_path(project)
+ )
end
end
describe '#tags_anchor_data' do
it 'returns tags data' do
- expect(presenter.tags_anchor_data).to have_attributes(is_link: true,
- label: a_string_including("#{project.repository.tags.size}"),
- link: presenter.project_tags_path(project))
+ expect(presenter.tags_anchor_data).to have_attributes(
+ is_link: true,
+ label: a_string_including("#{project.repository.tags.size}"),
+ link: presenter.project_tags_path(project)
+ )
end
end
@@ -232,10 +293,12 @@ describe ProjectPresenter do
it 'returns new file data if user can push' do
project.add_developer(user)
- expect(presenter.new_file_anchor_data).to have_attributes(is_link: false,
- label: a_string_including("New file"),
- link: presenter.project_new_blob_path(project, 'master'),
- class_modifier: 'success')
+ expect(presenter.new_file_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including("New file"),
+ link: presenter.project_new_blob_path(project, 'master'),
+ class_modifier: 'success'
+ )
end
it 'returns nil if user cannot push' do
@@ -243,7 +306,7 @@ describe ProjectPresenter do
end
context 'when the project is empty' do
- let(:project) { create(:project, :empty_repo) }
+ let_it_be(:project) { create(:project, :empty_repo) }
# Since we protect the default branch for empty repos
it 'is empty for a developer' do
@@ -258,11 +321,14 @@ describe ProjectPresenter do
context 'when user can push and README does not exists' do
it 'returns anchor data' do
project.add_developer(user)
+
allow(project.repository).to receive(:readme).and_return(nil)
- expect(presenter.readme_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Add README'),
- link: presenter.add_readme_path)
+ expect(presenter.readme_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Add README'),
+ link: presenter.add_readme_path
+ )
end
end
@@ -270,9 +336,11 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:readme).and_return(double(name: 'readme'))
- expect(presenter.readme_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('README'),
- link: presenter.readme_path)
+ expect(presenter.readme_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('README'),
+ link: presenter.readme_path
+ )
end
end
end
@@ -281,11 +349,14 @@ describe ProjectPresenter do
context 'when user can push and CHANGELOG does not exist' do
it 'returns anchor data' do
project.add_developer(user)
+
allow(project.repository).to receive(:changelog).and_return(nil)
- expect(presenter.changelog_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Add CHANGELOG'),
- link: presenter.add_changelog_path)
+ expect(presenter.changelog_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Add CHANGELOG'),
+ link: presenter.add_changelog_path
+ )
end
end
@@ -293,9 +364,11 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:changelog).and_return(double(name: 'foo'))
- expect(presenter.changelog_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('CHANGELOG'),
- link: presenter.changelog_path)
+ expect(presenter.changelog_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('CHANGELOG'),
+ link: presenter.changelog_path
+ )
end
end
end
@@ -304,11 +377,14 @@ describe ProjectPresenter do
context 'when user can push and LICENSE does not exist' do
it 'returns anchor data' do
project.add_developer(user)
+
allow(project.repository).to receive(:license_blob).and_return(nil)
- expect(presenter.license_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Add LICENSE'),
- link: presenter.add_license_path)
+ expect(presenter.license_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Add LICENSE'),
+ link: presenter.add_license_path
+ )
end
end
@@ -316,9 +392,11 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:license_blob).and_return(double(name: 'foo'))
- expect(presenter.license_anchor_data).to have_attributes(is_link: false,
- label: a_string_including(presenter.license_short_name),
- link: presenter.license_path)
+ expect(presenter.license_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including(presenter.license_short_name),
+ link: presenter.license_path
+ )
end
end
end
@@ -327,11 +405,14 @@ describe ProjectPresenter do
context 'when user can push and CONTRIBUTING does not exist' do
it 'returns anchor data' do
project.add_developer(user)
+
allow(project.repository).to receive(:contribution_guide).and_return(nil)
- expect(presenter.contribution_guide_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Add CONTRIBUTING'),
- link: presenter.add_contribution_guide_path)
+ expect(presenter.contribution_guide_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Add CONTRIBUTING'),
+ link: presenter.add_contribution_guide_path
+ )
end
end
@@ -339,9 +420,11 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project.repository).to receive(:contribution_guide).and_return(double(name: 'foo'))
- expect(presenter.contribution_guide_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('CONTRIBUTING'),
- link: presenter.contribution_guide_path)
+ expect(presenter.contribution_guide_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('CONTRIBUTING'),
+ link: presenter.contribution_guide_path
+ )
end
end
end
@@ -351,21 +434,26 @@ describe ProjectPresenter do
it 'returns anchor data' do
allow(project).to receive(:auto_devops_enabled?).and_return(true)
- expect(presenter.autodevops_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Auto DevOps enabled'),
- link: nil)
+ expect(presenter.autodevops_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Auto DevOps enabled'),
+ link: nil
+ )
end
end
context 'when user can admin pipeline and CI yml does not exist' do
it 'returns anchor data' do
project.add_maintainer(user)
+
allow(project).to receive(:auto_devops_enabled?).and_return(false)
allow(project.repository).to receive(:gitlab_ci_yml).and_return(nil)
- expect(presenter.autodevops_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Enable Auto DevOps'),
- link: presenter.project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ expect(presenter.autodevops_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Enable Auto DevOps'),
+ link: presenter.project_settings_ci_cd_path(project, anchor: 'autodevops-settings')
+ )
end
end
end
@@ -374,29 +462,37 @@ describe ProjectPresenter do
context 'when user can create Kubernetes cluster' do
it 'returns link to cluster if only one exists' do
project.add_maintainer(user)
+
cluster = create(:cluster, projects: [project])
- expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Kubernetes configured'),
- link: presenter.project_cluster_path(project, cluster))
+ expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Kubernetes configured'),
+ link: presenter.project_cluster_path(project, cluster)
+ )
end
it 'returns link to clusters page if more than one exists' do
project.add_maintainer(user)
+
create(:cluster, :production_environment, projects: [project])
create(:cluster, projects: [project])
- expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Kubernetes configured'),
- link: presenter.project_clusters_path(project))
+ expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Kubernetes configured'),
+ link: presenter.project_clusters_path(project)
+ )
end
it 'returns link to create a cluster if no cluster exists' do
project.add_maintainer(user)
- expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(is_link: false,
- label: a_string_including('Add Kubernetes cluster'),
- link: presenter.new_project_cluster_path(project))
+ expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(
+ is_link: false,
+ label: a_string_including('Add Kubernetes cluster'),
+ link: presenter.new_project_cluster_path(project)
+ )
end
end
@@ -464,7 +560,7 @@ describe ProjectPresenter do
end
context 'initialized repo' do
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
it 'orders the items correctly' do
expect(empty_repo_statistics_buttons.map(&:label)).to start_with(