Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1850d48925
commit
a87ae2e97e
|
@ -183,6 +183,35 @@ RSpec/ContextWording:
|
|||
RSpec/ExpectChange:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 47
|
||||
RSpec/ExpectGitlabTracking:
|
||||
Exclude:
|
||||
- 'ee/spec/controllers/groups/analytics/coverage_reports_controller_spec.rb'
|
||||
- 'ee/spec/controllers/projects/settings/operations_controller_spec.rb'
|
||||
- 'ee/spec/controllers/registrations_controller_spec.rb'
|
||||
- 'ee/spec/requests/api/visual_review_discussions_spec.rb'
|
||||
- 'ee/spec/services/epics/issue_promote_service_spec.rb'
|
||||
- 'spec/controllers/groups/registry/repositories_controller_spec.rb'
|
||||
- 'spec/controllers/groups_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/repositories_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/tags_controller_spec.rb'
|
||||
- 'spec/controllers/projects/settings/operations_controller_spec.rb'
|
||||
- 'spec/controllers/registrations_controller_spec.rb'
|
||||
- 'spec/lib/api/helpers_spec.rb'
|
||||
- 'spec/lib/gitlab/experimentation_spec.rb'
|
||||
- 'spec/mailers/notify_spec.rb'
|
||||
- 'spec/models/project_services/prometheus_service_spec.rb'
|
||||
- 'spec/requests/api/project_container_repositories_spec.rb'
|
||||
- 'spec/services/clusters/applications/check_installation_progress_service_spec.rb'
|
||||
- 'spec/services/issues/zoom_link_service_spec.rb'
|
||||
- 'spec/support/helpers/snowplow_helpers.rb'
|
||||
- 'spec/support/shared_examples/controllers/trackable_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/discussions_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/tracking_shared_examples.rb'
|
||||
- 'spec/support/snowplow.rb'
|
||||
|
||||
# Offense count: 751
|
||||
RSpec/ExpectInHook:
|
||||
Enabled: false
|
||||
|
|
|
@ -44,7 +44,6 @@ export default {
|
|||
type="search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<i class="fa fa-search dropdown-input-search" aria-hidden="true" data-hidden="true"> </i>
|
||||
<gl-icon name="search" class="dropdown-input-search" aria-hidden="true" data-hidden="true" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -96,10 +96,6 @@
|
|||
content: '\f00c';
|
||||
}
|
||||
|
||||
.fa-search::before {
|
||||
content: '\f002';
|
||||
}
|
||||
|
||||
.fa-warning::before,
|
||||
.fa-exclamation-triangle::before {
|
||||
content: '\f071';
|
||||
|
@ -221,14 +217,6 @@
|
|||
content: '\f04b';
|
||||
}
|
||||
|
||||
.fa-search-plus::before {
|
||||
content: '\f00e';
|
||||
}
|
||||
|
||||
.fa-search-minus::before {
|
||||
content: '\f010';
|
||||
}
|
||||
|
||||
.fa-share::before {
|
||||
content: '\f064';
|
||||
}
|
||||
|
|
|
@ -35,22 +35,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.issuable-list-root {
|
||||
.gl-label-link {
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.svg-container.jira-logo-container {
|
||||
svg {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.user-can-drag {
|
||||
cursor: grab;
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ input[type='checkbox']:hover {
|
|||
.search-icon {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
top: 9px;
|
||||
color: $gray-darkest;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ module DropdownsHelper
|
|||
def dropdown_filter(placeholder, search_id: nil)
|
||||
content_tag :div, class: "dropdown-input" do
|
||||
filter_output = search_field_tag search_id, nil, class: "dropdown-input-field qa-dropdown-input-field", placeholder: placeholder, autocomplete: 'off'
|
||||
filter_output << icon('search', class: "dropdown-input-search")
|
||||
filter_output << sprite_icon('search', css_class: 'dropdown-input-search')
|
||||
filter_output << sprite_icon('close', size: 16, css_class: 'dropdown-input-clear js-dropdown-input-clear')
|
||||
|
||||
filter_output.html_safe
|
||||
|
|
|
@ -46,7 +46,8 @@ module Ci
|
|||
terraform: 'tfplan.json',
|
||||
cluster_applications: 'gl-cluster-applications.json',
|
||||
requirements: 'requirements.json',
|
||||
coverage_fuzzing: 'gl-coverage-fuzzing.json'
|
||||
coverage_fuzzing: 'gl-coverage-fuzzing.json',
|
||||
api_fuzzing: 'gl-api-fuzzing-report.json'
|
||||
}.freeze
|
||||
|
||||
INTERNAL_TYPES = {
|
||||
|
@ -82,11 +83,13 @@ module Ci
|
|||
load_performance: :raw,
|
||||
terraform: :raw,
|
||||
requirements: :raw,
|
||||
coverage_fuzzing: :raw
|
||||
coverage_fuzzing: :raw,
|
||||
api_fuzzing: :raw
|
||||
}.freeze
|
||||
|
||||
DOWNLOADABLE_TYPES = %w[
|
||||
accessibility
|
||||
api_fuzzing
|
||||
archive
|
||||
cobertura
|
||||
codequality
|
||||
|
@ -194,7 +197,8 @@ module Ci
|
|||
requirements: 22, ## EE-specific
|
||||
coverage_fuzzing: 23, ## EE-specific
|
||||
browser_performance: 24, ## EE-specific
|
||||
load_performance: 25 ## EE-specific
|
||||
load_performance: 25, ## EE-specific
|
||||
api_fuzzing: 26 ## EE-specific
|
||||
}
|
||||
|
||||
# `file_location` indicates where actual files are stored.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
- project_name = params[:name].present? ? params[:name] : nil
|
||||
.search-field-holder
|
||||
= search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' }
|
||||
= icon("search", class: "search-icon")
|
||||
= sprite_icon('search', css_class: 'search-icon')
|
||||
= render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
|
||||
= link_to new_admin_group_path, class: "btn btn-success" do
|
||||
= _('New group')
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
= search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { qa_selector: 'user_search_field' }
|
||||
- if @sort.present?
|
||||
= hidden_field_tag :sort, @sort
|
||||
= icon("search", class: "search-icon")
|
||||
= sprite_icon('search', css_class: 'search-icon')
|
||||
= button_tag s_('AdminUsers|Search users') if Rails.env.test?
|
||||
.dropdown.user-sort-dropdown
|
||||
= label_tag 'Sort by', nil, class: 'label-bold'
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
.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.")
|
||||
= 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.")
|
||||
= 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 => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :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.")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- max_name_length = 255
|
||||
- max_first_name_length = max_last_name_length = 127
|
||||
- max_username_length = 255
|
||||
- min_username_length = 2
|
||||
#register-pane.tab-pane.login-box{ role: 'tabpanel' }
|
||||
|
@ -8,9 +8,13 @@
|
|||
= render "devise/shared/error_messages", resource: resource
|
||||
- if Feature.enabled?(:invisible_captcha)
|
||||
= invisible_captcha
|
||||
.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_("SignUp|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.")
|
||||
.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_first_name_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_last_name_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 => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :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.")
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
= form_tag project_network_path(@project, @id), method: :get, class: 'form-inline network-form' do |f|
|
||||
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: _("Git revision"), class: 'search-input form-control input-mx-250 search-sha'
|
||||
= button_tag class: 'btn btn-success' do
|
||||
= icon('search')
|
||||
= sprite_icon('search')
|
||||
.inline.prepend-left-20
|
||||
.form-check.light
|
||||
= check_box_tag :filter_ref, 1, @options[:filter_ref], class: 'form-check-input'
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
.position-relative
|
||||
= search_field_tag :search, params[:search], { placeholder: _('Find existing members by name'), class: 'form-control', spellcheck: false }
|
||||
%button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") }
|
||||
= icon("search")
|
||||
= sprite_icon('search', css_class: 'gl-vertical-align-middle!')
|
||||
= label_tag :sort_by, _('Sort by'), class: 'col-form-label label-bold px-2'
|
||||
= render 'shared/members/sort_dropdown'
|
||||
%ul.content-list.members-list{ data: { qa_selector: 'members_list' } }
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
.position-relative
|
||||
= search_field_tag :search, params[:search], { placeholder: _('Search'), class: 'form-control', spellcheck: false }
|
||||
%button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") }
|
||||
= icon("search")
|
||||
= sprite_icon('search')
|
||||
.dropdown.inline.user-sort-dropdown
|
||||
= dropdown_toggle(starrers_sort_options_hash[@sort], { toggle: 'dropdown' })
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
= _("What are you searching for?")
|
||||
.position-relative
|
||||
= search_field_tag :search, params[:search], placeholder: _("Search for projects, issues, etc."), class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
|
||||
= icon("search", class: "search-icon")
|
||||
= sprite_icon('search', css_class: 'search-icon')
|
||||
%button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
|
||||
= sprite_icon('clear')
|
||||
%span.sr-only
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.search_box
|
||||
.search_glyph
|
||||
%h4
|
||||
= icon('search')
|
||||
= sprite_icon('search', size: 24, css_class: 'gl-vertical-align-text-bottom')
|
||||
= search_entries_empty_message(@scope, @search_term)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
= search_field_tag :search, params[:search], { placeholder: _('Filter'), id: 'label-search', class: 'form-control search-text-input input-short', spellcheck: false, autofocus: true }
|
||||
%span.input-group-append
|
||||
%button.btn.gl-button.btn-default{ type: "submit", "aria-label" => _('Submit search') }
|
||||
= icon("search")
|
||||
= sprite_icon('search')
|
||||
= render 'shared/labels/sort_dropdown'
|
||||
- if labels_or_filters && can_admin_label && @project
|
||||
= link_to _('New label'), new_project_label_path(@project), class: "btn gl-button btn-success qa-label-create-new"
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
autofocus: local_assigns[:autofocus]
|
||||
|
||||
- if local_assigns[:icon]
|
||||
= icon("search", class: "search-icon")
|
||||
= sprite_icon('search', css_class: 'search-icon')
|
||||
|
||||
- if params[:sort].present?
|
||||
= hidden_field_tag :sort, params[:sort]
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Return nil when fetching a wiki page with invalid arguments
|
||||
merge_request: 44302
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace fa-search with GitLab SVG search icon
|
||||
merge_request: 43110
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Split name to first and last name for signup
|
||||
merge_request: 42346
|
||||
author:
|
||||
type: changed
|
|
@ -221,6 +221,7 @@ Kibana
|
|||
Kinesis
|
||||
Knative
|
||||
Kramdown
|
||||
Kubecost
|
||||
kubectl
|
||||
Kubernetes
|
||||
Kubesec
|
||||
|
|
|
@ -16654,6 +16654,11 @@ type ScannedResourceEdge {
|
|||
Represents summary of a security report
|
||||
"""
|
||||
type SecurityReportSummary {
|
||||
"""
|
||||
Aggregated counts for the api_fuzzing scan
|
||||
"""
|
||||
apiFuzzing: SecurityReportSummarySection
|
||||
|
||||
"""
|
||||
Aggregated counts for the container_scanning scan
|
||||
"""
|
||||
|
@ -16734,6 +16739,7 @@ type SecurityReportSummarySection {
|
|||
The type of the security scanner
|
||||
"""
|
||||
enum SecurityScannerType {
|
||||
API_FUZZING
|
||||
CONTAINER_SCANNING
|
||||
COVERAGE_FUZZING
|
||||
DAST
|
||||
|
@ -20173,7 +20179,7 @@ type Vulnerability implements Noteable {
|
|||
"""
|
||||
Type of the security report that found the vulnerability (SAST,
|
||||
DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION,
|
||||
COVERAGE_FUZZING)
|
||||
COVERAGE_FUZZING, API_FUZZING)
|
||||
"""
|
||||
reportType: VulnerabilityReportType
|
||||
|
||||
|
@ -20636,6 +20642,7 @@ type VulnerabilityPermissions {
|
|||
The type of the security scan that found the vulnerability
|
||||
"""
|
||||
enum VulnerabilityReportType {
|
||||
API_FUZZING
|
||||
CONTAINER_SCANNING
|
||||
COVERAGE_FUZZING
|
||||
DAST
|
||||
|
|
|
@ -48143,6 +48143,20 @@
|
|||
"name": "SecurityReportSummary",
|
||||
"description": "Represents summary of a security report",
|
||||
"fields": [
|
||||
{
|
||||
"name": "apiFuzzing",
|
||||
"description": "Aggregated counts for the api_fuzzing scan",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "SecurityReportSummarySection",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "containerScanning",
|
||||
"description": "Aggregated counts for the container_scanning scan",
|
||||
|
@ -48386,6 +48400,12 @@
|
|||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "API_FUZZING",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
|
@ -58532,7 +58552,7 @@
|
|||
},
|
||||
{
|
||||
"name": "reportType",
|
||||
"description": "Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING)",
|
||||
"description": "Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING)",
|
||||
"args": [
|
||||
|
||||
],
|
||||
|
@ -59983,6 +60003,12 @@
|
|||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "API_FUZZING",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
|
|
|
@ -2246,6 +2246,7 @@ Represents summary of a security report.
|
|||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `apiFuzzing` | SecurityReportSummarySection | Aggregated counts for the api_fuzzing scan |
|
||||
| `containerScanning` | SecurityReportSummarySection | Aggregated counts for the container_scanning scan |
|
||||
| `coverageFuzzing` | SecurityReportSummarySection | Aggregated counts for the coverage_fuzzing scan |
|
||||
| `dast` | SecurityReportSummarySection | Aggregated counts for the dast scan |
|
||||
|
@ -2817,7 +2818,7 @@ Represents a vulnerability.
|
|||
| `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability |
|
||||
| `primaryIdentifier` | VulnerabilityIdentifier | Primary identifier of the vulnerability. |
|
||||
| `project` | Project | The project on which the vulnerability was found |
|
||||
| `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING) |
|
||||
| `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING) |
|
||||
| `resolvedOnDefaultBranch` | Boolean! | Indicates whether the vulnerability is fixed on the default branch or not |
|
||||
| `scanner` | VulnerabilityScanner | Scanner metadata for the vulnerability. |
|
||||
| `severity` | VulnerabilitySeverity | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
|
@ -3551,6 +3552,7 @@ The type of the security scanner.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `API_FUZZING` | |
|
||||
| `CONTAINER_SCANNING` | |
|
||||
| `COVERAGE_FUZZING` | |
|
||||
| `DAST` | |
|
||||
|
@ -3735,6 +3737,7 @@ The type of the security scan that found the vulnerability.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `API_FUZZING` | |
|
||||
| `CONTAINER_SCANNING` | |
|
||||
| `COVERAGE_FUZZING` | |
|
||||
| `DAST` | |
|
||||
|
|
|
@ -361,7 +361,7 @@ POST /projects/:id/releases
|
|||
| `tag_name` | string | yes | The tag where the release will be created from. |
|
||||
| `description` | string | no | The description of the release. You can use [Markdown](../../user/markdown.md). |
|
||||
| `ref` | string | yes, if `tag_name` doesn't exist | If a tag specified in `tag_name` doesn't exist, the release will be created from `ref` and tagged with `tag_name`. It can be a commit SHA, another tag name, or a branch name. |
|
||||
| `milestones` | array of string | no | The title of each milestone the release is associated with. |
|
||||
| `milestones` | array of string | no | The title of each milestone the release is associated with. [GitLab Premium](https://about.gitlab.com/pricing/) customers can specify group milestones. |
|
||||
| `assets:links` | array of hash | no | An array of assets links. |
|
||||
| `assets:links:name`| string | required by: `assets:links` | The name of the link. |
|
||||
| `assets:links:url` | string | required by: `assets:links` | The URL of the link. |
|
||||
|
@ -484,6 +484,15 @@ Example response:
|
|||
}
|
||||
```
|
||||
|
||||
### Group milestones **(PREMIUM ONLY)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235391) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
|
||||
|
||||
Group milestones associated with the project may be specified in the `milestones`
|
||||
array for [Create a release](#create-a-release) and [Update a release](#update-a-release)
|
||||
API calls. Only milestones associated with the project's group may be specified, and
|
||||
adding milestones for ancestor groups will raise an error.
|
||||
|
||||
## Collect release evidence **(PREMIUM ONLY)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
|
||||
|
@ -525,7 +534,7 @@ PUT /projects/:id/releases/:tag_name
|
|||
| `tag_name` | string | yes | The tag where the release will be created from. |
|
||||
| `name` | string | no | The release name. |
|
||||
| `description` | string | no | The description of the release. You can use [Markdown](../../user/markdown.md). |
|
||||
| `milestones` | array of string | no | The title of each milestone to associate with the release (`[]` to remove all milestones from the release). |
|
||||
| `milestones` | array of string | no | The title of each milestone to associate with the release. [GitLab Premium](https://about.gitlab.com/pricing/) customers can specify group milestones. To remove all milestones from the release, specify `[]`. |
|
||||
| `released_at` | datetime | no | The date when the release will be/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
|
||||
|
||||
Example request:
|
||||
|
|
|
@ -25,7 +25,7 @@ the repository.
|
|||
|
||||
The [Scalability
|
||||
team](https://about.gitlab.com/handbook/engineering/infrastructure/team/scalability/)
|
||||
currently maintains the `stages.yml` file. They will automatically be
|
||||
currently maintains the `feature_categories.yml` file. They will automatically be
|
||||
notified on Slack when the file becomes outdated.
|
||||
|
||||
## Sidekiq workers
|
||||
|
|
|
@ -24,7 +24,7 @@ To create a project in GitLab:
|
|||
- Run [CI/CD pipelines for external repositories](../ci/ci_cd_for_external_repos/index.md). **(PREMIUM)**
|
||||
|
||||
NOTE: **Note:**
|
||||
For a list of words that cannot be used as project names see
|
||||
For a list of words that can't be used as project names see
|
||||
[Reserved project and group names](../user/reserved_names.md).
|
||||
|
||||
### Blank projects
|
||||
|
@ -33,7 +33,7 @@ To create a new blank project on the **New project** page:
|
|||
|
||||
1. On the **Blank project** tab, provide the following information:
|
||||
- The name of your project in the **Project name** field. You can't use
|
||||
special characters, but you can use spaces, hyphens, underscores or even
|
||||
special characters, but you can use spaces, hyphens, underscores, or even
|
||||
emoji. When adding the name, the **Project slug** will auto populate.
|
||||
The slug is what the GitLab instance will use as the URL path to the project.
|
||||
If you want a different slug, input the project name first,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
stage: Configure
|
||||
group: Configure
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Cluster cost management
|
||||
|
||||
Cluster cost management provides insights into cluster resource usage. GitLab provides an example
|
||||
[`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
|
||||
project that uses GitLab's Prometheus integration and
|
||||
[Kubecost's `cost-model`](https://github.com/kubecost/cost-model) to provide cluster cost
|
||||
insights within GitLab:
|
||||
|
||||
![Example dashboard](img/kubecost_v13_5.png)
|
||||
|
||||
## Configure cluster cost management
|
||||
|
||||
To get started with cluster cost management, you need [Maintainer](../permissions.md)
|
||||
permissions in a project or group.
|
||||
|
||||
1. Clone the [`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
|
||||
example repository, which contains minor modifications to the upstream Kubecost
|
||||
`cost-model` project:
|
||||
- Configures your Prometheus endpoint to the GitLab-managed Prometheus. You may
|
||||
need to change this value if you use a non-managed Prometheus.
|
||||
- Adds the necessary annotations to the deployment manifest to be scraped by
|
||||
GitLab-managed Prometheus.
|
||||
- Changes the Google Pricing API access key to GitLab's access key.
|
||||
- Contains definitions for a custom GitLab Metrics dashboard to show the cost insights.
|
||||
1. Connect GitLab with Prometheus, depending on your configuration:
|
||||
- *If Prometheus is already configured,* navigate to **Settings > Integrations > Prometheus**
|
||||
to provide the API endpoint of your Prometheus server.
|
||||
- *For GitLab-managed Prometheus,* navigate to your cluster's **Details** page,
|
||||
select the **Applications** tab, and install Prometheus. The integration is
|
||||
auto-configured for you.
|
||||
1. Set up the Prometheus integration on the cloned example project.
|
||||
1. Add the Kubecost `cost-model` to your cluster:
|
||||
- *For non-managed clusters*, deploy it with GitLab CI/CD.
|
||||
- *To deploy it manually*, use the following commands:
|
||||
|
||||
```shell
|
||||
kubectl create namespace cost-model
|
||||
kubectl apply -f kubernetes/ --namespace cost-model
|
||||
```
|
||||
|
||||
To access the cost insights, navigate to **Operations > Metrics** and select
|
||||
the `default_costs.yml` dashboard. You can [customize](#customize-the-cost-dashboard)
|
||||
this dashboard.
|
||||
|
||||
### Customize the cost dashboard
|
||||
|
||||
You can customize the cost dashboard by editing the `.gitlab/dashboards/default_costs.yml`
|
||||
file or creating similar dashboard configuration files. To learn more, read about
|
||||
[customizing dashboards in our documentation](/ee/operations/metrics/dashboards/).
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
|
@ -17,7 +17,7 @@ GitLab's [SCIM API](../../../api/scim.md) implements part of [the RFC7644 protoc
|
|||
|
||||
## Features
|
||||
|
||||
Currently, the following actions are available:
|
||||
The following actions are available:
|
||||
|
||||
- Create users
|
||||
- Update users (Azure only)
|
||||
|
@ -51,7 +51,7 @@ Once [Group Single Sign-On](index.md) has been configured, we can:
|
|||
|
||||
The SAML application that was created during [Single sign-on](index.md) setup for [Azure](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/view-applications-portal) now needs to be set up for SCIM.
|
||||
|
||||
1. Check the configuration for your GitLab SAML app and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This will match the `extern_uid` used on GitLab.
|
||||
1. Check the configuration for your GitLab SAML app and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This matches the `extern_uid` used on GitLab.
|
||||
|
||||
![Name identifier value mapping](img/scim_name_identifier_mapping.png)
|
||||
|
||||
|
@ -63,7 +63,7 @@ During this configuration, note the following:
|
|||
- The `Tenant URL` and `secret token` are the ones retrieved in the
|
||||
[previous step](#gitlab-configuration).
|
||||
- Should there be any problems with the availability of GitLab or similar
|
||||
errors, the notification email set will get those.
|
||||
errors, the notification email set gets those.
|
||||
- It is recommended to set a notification email and check the **Send an email notification when a failure occurs** checkbox.
|
||||
- For mappings, we will only leave `Synchronize Azure Active Directory Users to AppName` enabled.
|
||||
|
||||
|
@ -75,10 +75,10 @@ You can then test the connection by clicking on **Test Connection**. If the conn
|
|||
1. Click **Delete** next to the `mail` mapping.
|
||||
1. Map `userPrincipalName` to `emails[type eq "work"].value` and change its **Matching precedence** to `2`.
|
||||
1. Map `mailNickname` to `userName`.
|
||||
1. Determine how GitLab will uniquely identify users.
|
||||
1. Determine how GitLab uniquely identifies users.
|
||||
|
||||
- Use `objectId` unless users already have SAML linked for your group.
|
||||
- If you already have users with SAML linked then use the `Name ID` value from the [SAML configuration](#azure). Using a different value will likely cause duplicate users and prevent users from accessing the GitLab group.
|
||||
- If you already have users with SAML linked then use the `Name ID` value from the [SAML configuration](#azure). Using a different value may cause duplicate users and prevent users from accessing the GitLab group.
|
||||
|
||||
1. Create a new mapping:
|
||||
1. Click **Add New Mapping**.
|
||||
|
@ -110,14 +110,14 @@ You can then test the connection by clicking on **Test Connection**. If the conn
|
|||
|
||||
NOTE: **Note:**
|
||||
You can control what is actually synced by selecting the `Scope`. For example,
|
||||
`Sync only assigned users and groups` will only sync the users assigned to
|
||||
the application (`Users and groups`), otherwise, it will sync the whole Active Directory.
|
||||
`Sync only assigned users and groups` only syncs the users assigned to
|
||||
the application (`Users and groups`), otherwise, it syncs the whole Active Directory.
|
||||
|
||||
Once enabled, the synchronization details and any errors will appear on the
|
||||
Once enabled, the synchronization details and any errors appears on the
|
||||
bottom of the **Provisioning** screen, together with a link to the audit logs.
|
||||
|
||||
CAUTION: **Warning:**
|
||||
Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group.
|
||||
Once synchronized, changing the field mapped to `id` and `externalId` may cause a number of errors. These include provisioning errors, duplicate users, and may prevent existing users from accessing the GitLab group.
|
||||
|
||||
### Okta configuration steps
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ type: reference, howto
|
|||
> - It's recommended for production use.
|
||||
> - For GitLab self-managed instances, GitLab administrators can [disable it](#enable-or-disable-project-access-tokens).
|
||||
|
||||
Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens). You can also use project access tokens with Git to authenticate over HTTP or SSH.
|
||||
Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens). You can also use project access tokens with Git to authenticate over HTTP.
|
||||
|
||||
Project access tokens expire on the date you define, at midnight UTC.
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ module.exports = path => {
|
|||
reporters.push([
|
||||
'jest-junit',
|
||||
{
|
||||
output: './junit_jest.xml',
|
||||
outputName: './junit_jest.xml',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ module Gitlab
|
|||
%i[junit codequality sast secret_detection dependency_scanning container_scanning
|
||||
dast performance browser_performance load_performance license_management license_scanning metrics lsif
|
||||
dotenv cobertura terraform accessibility cluster_applications
|
||||
requirements coverage_fuzzing].freeze
|
||||
requirements coverage_fuzzing api_fuzzing].freeze
|
||||
|
||||
attributes ALLOWED_KEYS
|
||||
|
||||
|
@ -25,6 +25,7 @@ module Gitlab
|
|||
|
||||
with_options allow_nil: true do
|
||||
validates :junit, array_of_strings_or_string: true
|
||||
validates :api_fuzzing, array_of_strings_or_string: true
|
||||
validates :coverage_fuzzing, array_of_strings_or_string: true
|
||||
validates :sast, array_of_strings_or_string: true
|
||||
validates :sast, array_of_strings_or_string: true
|
||||
|
|
|
@ -100,10 +100,6 @@ module Gitlab
|
|||
wrapped_gitaly_errors do
|
||||
gitaly_find_page(title: title, version: version, dir: dir)
|
||||
end
|
||||
rescue Gitlab::Git::CommandError
|
||||
# Return nil for invalid versions.
|
||||
# This can be removed with https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2323 in place.
|
||||
nil
|
||||
end
|
||||
|
||||
def file(name, version)
|
||||
|
@ -159,6 +155,8 @@ module Gitlab
|
|||
return unless wiki_page
|
||||
|
||||
Gitlab::Git::WikiPage.new(wiki_page, version)
|
||||
rescue GRPC::InvalidArgument
|
||||
nil
|
||||
end
|
||||
|
||||
def gitaly_find_file(name, version)
|
||||
|
|
|
@ -1305,6 +1305,9 @@ msgstr ""
|
|||
msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
|
||||
msgstr ""
|
||||
|
||||
msgid "API Fuzzing"
|
||||
msgstr ""
|
||||
|
||||
msgid "API Help"
|
||||
msgstr ""
|
||||
|
||||
|
@ -11365,6 +11368,9 @@ msgstr ""
|
|||
msgid "Find File"
|
||||
msgstr ""
|
||||
|
||||
msgid "Find bugs in your code with API fuzzing."
|
||||
msgstr ""
|
||||
|
||||
msgid "Find bugs in your code with coverage-guided fuzzing."
|
||||
msgstr ""
|
||||
|
||||
|
@ -11398,9 +11404,6 @@ msgstr ""
|
|||
msgid "Finished"
|
||||
msgstr ""
|
||||
|
||||
msgid "First Name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "First Seen"
|
||||
msgstr ""
|
||||
|
||||
|
@ -11410,6 +11413,9 @@ msgstr ""
|
|||
msgid "First name"
|
||||
msgstr ""
|
||||
|
||||
msgid "First name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "First seen"
|
||||
msgstr ""
|
||||
|
||||
|
@ -14893,9 +14899,6 @@ msgstr ""
|
|||
msgid "Last Accessed On"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last Name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Last Pipeline"
|
||||
msgstr ""
|
||||
|
||||
|
@ -14929,6 +14932,9 @@ msgstr ""
|
|||
msgid "Last name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Last name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Last reply by"
|
||||
msgstr ""
|
||||
|
||||
|
@ -23918,9 +23924,6 @@ msgstr ""
|
|||
msgid "SignUp|Last Name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "SignUp|Name is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
msgid "SignUp|Username is too long (maximum is %{max_length} characters)."
|
||||
msgstr ""
|
||||
|
||||
|
@ -28021,6 +28024,12 @@ msgstr ""
|
|||
msgid "UsageQuota|This namespace has no projects which use shared runners"
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|This project is at risk of being locked."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|This project is locked."
|
||||
msgstr ""
|
||||
|
||||
msgid "UsageQuota|Unlimited"
|
||||
msgstr ""
|
||||
|
||||
|
|
23
package.json
23
package.json
|
@ -42,8 +42,8 @@
|
|||
"@babel/plugin-syntax-import-meta": "^7.10.1",
|
||||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.5",
|
||||
"@gitlab/svgs": "1.170.0",
|
||||
"@gitlab/ui": "21.16.0",
|
||||
"@gitlab/svgs": "1.171.0",
|
||||
"@gitlab/ui": "21.22.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "^6.0.3-3",
|
||||
"@rails/ujs": "^6.0.3-2",
|
||||
|
@ -167,9 +167,9 @@
|
|||
"@vue/test-utils": "1.0.0-beta.30",
|
||||
"acorn": "^6.3.0",
|
||||
"axios-mock-adapter": "^1.15.0",
|
||||
"babel-jest": "^24.1.0",
|
||||
"babel-plugin-dynamic-import-node": "^2.2.0",
|
||||
"babel-plugin-istanbul": "^5.1.0",
|
||||
"babel-jest": "^26.5.2",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-istanbul": "^6.0.0",
|
||||
"chalk": "^2.4.1",
|
||||
"commander": "^2.18.0",
|
||||
"custom-jquery-matchers": "^2.1.0",
|
||||
|
@ -187,11 +187,11 @@
|
|||
"jasmine-core": "^2.9.0",
|
||||
"jasmine-diff": "^0.1.3",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"jest": "^24.1.0",
|
||||
"jest": "^26.5.2",
|
||||
"jest-canvas-mock": "^2.1.2",
|
||||
"jest-environment-jsdom-sixteen": "^1.0.0",
|
||||
"jest-junit": "^6.3.0",
|
||||
"jest-util": "^24.0.0",
|
||||
"jest-environment-jsdom": "^26.5.2",
|
||||
"jest-junit": "^12.0.0",
|
||||
"jest-util": "^26.5.2",
|
||||
"jsdoc": "^3.5.5",
|
||||
"jsdoc-vue": "^1.0.0",
|
||||
"karma": "^4.2.0",
|
||||
|
@ -214,7 +214,7 @@
|
|||
"stylelint-config-recommended": "^2.2.0",
|
||||
"stylelint-scss": "^3.9.2",
|
||||
"timezone-mock": "^1.0.8",
|
||||
"vue-jest": "4.0.0-beta.2",
|
||||
"vue-jest": "4.0.0-rc.0",
|
||||
"webpack-dev-server": "^3.10.3",
|
||||
"xhr-mock": "^2.5.1",
|
||||
"yarn-check-webpack-plugin": "^1.2.0",
|
||||
|
@ -225,8 +225,7 @@
|
|||
},
|
||||
"resolutions": {
|
||||
"chokidar": "^3.4.0",
|
||||
"monaco-editor": "0.20.0",
|
||||
"vue-jest/ts-jest": "24.0.0"
|
||||
"monaco-editor": "0.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0",
|
||||
|
|
|
@ -5,7 +5,8 @@ module QA
|
|||
module Main
|
||||
class SignUp < Page::Base
|
||||
view 'app/views/devise/shared/_signup_box.html.haml' do
|
||||
element :new_user_name_field
|
||||
element :new_user_first_name_field
|
||||
element :new_user_last_name_field
|
||||
element :new_user_username_field
|
||||
element :new_user_email_field
|
||||
element :new_user_password_field
|
||||
|
@ -18,7 +19,8 @@ module QA
|
|||
end
|
||||
|
||||
def sign_up!(user)
|
||||
fill_element :new_user_name_field, user.name
|
||||
fill_element :new_user_first_name_field, user.first_name
|
||||
fill_element :new_user_last_name_field, user.last_name
|
||||
fill_element :new_user_username_field, user.username
|
||||
fill_element :new_user_email_field, user.email
|
||||
fill_element :new_user_password_field, user.password
|
||||
|
|
|
@ -11,6 +11,8 @@ module QA
|
|||
|
||||
attribute :id
|
||||
attribute :name
|
||||
attribute :first_name
|
||||
attribute :last_name
|
||||
attribute :email
|
||||
|
||||
def initialize
|
||||
|
@ -34,6 +36,14 @@ module QA
|
|||
@name ||= api_resource&.dig(:name) || "QA User #{unique_id}"
|
||||
end
|
||||
|
||||
def first_name
|
||||
name.split(' ').first
|
||||
end
|
||||
|
||||
def last_name
|
||||
name.split(' ').drop(1).join(' ')
|
||||
end
|
||||
|
||||
def email
|
||||
@email ||= begin
|
||||
api_email = api_resource&.dig(:email)
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rack/utils'
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module RSpec
|
||||
# This cop checks for `expect(Gitlab::Tracking).to receive(:event)` usage in specs.
|
||||
# See /spec/support/helpers/snowplow_helpers.rb for details on the replacement.
|
||||
#
|
||||
# @example
|
||||
#
|
||||
# # bad
|
||||
# it 'expects a snowplow event' do
|
||||
# expect(Gitlab::Tracking).to receive(:event).with("Category", "action", ...)
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it 'expects a snowplow event', :snowplow do
|
||||
# expect_snowplow_event(category: "Category", action: "action", ...)
|
||||
# end
|
||||
#
|
||||
# # bad
|
||||
# it 'does not expect a snowplow event' do
|
||||
# expect(Gitlab::Tracking).not_to receive(:event)
|
||||
# end
|
||||
#
|
||||
# # good
|
||||
# it 'does not expect a snowplow event', :snowplow do
|
||||
# expect_no_snowplow_event
|
||||
# end
|
||||
class ExpectGitlabTracking < RuboCop::Cop::Cop
|
||||
MSG = 'Do not expect directly on `Gitlab::Tracking#event`, add the `snowplow` annotation and use ' \
|
||||
'`expect_snowplow_event` instead. ' \
|
||||
'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#test-snowplow-events'
|
||||
|
||||
def_node_matcher :expect_gitlab_tracking?, <<~PATTERN
|
||||
(send
|
||||
(send nil? {:expect :allow}
|
||||
(const (const nil? :Gitlab) :Tracking)
|
||||
)
|
||||
${:to :to_not :not_to}
|
||||
{
|
||||
(
|
||||
send nil? {:receive :have_received} (sym :event) ...
|
||||
)
|
||||
|
||||
(send
|
||||
(send nil? {:receive :have_received} (sym :event)) ...
|
||||
)
|
||||
}
|
||||
...
|
||||
)
|
||||
PATTERN
|
||||
|
||||
RESTRICT_ON_SEND = [:expect, :allow].freeze
|
||||
|
||||
def on_send(node)
|
||||
return unless expect_gitlab_tracking?(node)
|
||||
|
||||
add_offense(node)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -80,7 +80,7 @@ RSpec.describe RegistrationsController do
|
|||
end
|
||||
|
||||
describe '#create' do
|
||||
let(:base_user_params) { { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
|
||||
let(:base_user_params) { { first_name: 'first', last_name: 'last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
|
||||
let(:user_params) { { user: base_user_params } }
|
||||
|
||||
context 'email confirmation' do
|
||||
|
@ -370,21 +370,12 @@ RSpec.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
|
||||
it 'sets name from first and last name' do
|
||||
post :create, params: { new_user: base_user_params }
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
|
|||
end
|
||||
|
||||
def fill_in_sign_up_form(new_user)
|
||||
fill_in 'new_user_name', with: new_user.name
|
||||
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
|
||||
|
|
|
@ -7,6 +7,14 @@ RSpec.shared_examples 'Signup' do
|
|||
|
||||
let(:new_user) { build_stubbed(:user) }
|
||||
|
||||
def fill_in_signup_form
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
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_password', with: new_user.password
|
||||
end
|
||||
|
||||
describe 'username validation', :js do
|
||||
before do
|
||||
visit new_user_registration_path
|
||||
|
@ -144,20 +152,9 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'creates the user account and sends a confirmation email' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
|
||||
expect { click_button 'Register' }.to change { User.count }.by(1)
|
||||
|
||||
expect(current_path).to eq users_almost_there_path
|
||||
expect(page).to have_content('Please check your email to confirm your account')
|
||||
end
|
||||
|
@ -171,46 +168,14 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'creates the user account and sends a confirmation email' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
|
||||
expect { click_button 'Register' }.to change { User.count }.by(1)
|
||||
|
||||
expect(current_path).to eq users_sign_up_welcome_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when sigining up with different cased emails" do
|
||||
it "creates the user successfully" do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
click_button "Register"
|
||||
|
||||
expect(current_path).to eq users_sign_up_welcome_path
|
||||
end
|
||||
end
|
||||
|
||||
context "when not sending confirmation email" do
|
||||
before do
|
||||
stub_application_setting(send_user_confirmation_email: false)
|
||||
|
@ -219,17 +184,7 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'creates the user account and goes to dashboard' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
click_button "Register"
|
||||
|
||||
expect(current_path).to eq users_sign_up_welcome_path
|
||||
|
@ -239,20 +194,10 @@ RSpec.shared_examples 'Signup' do
|
|||
|
||||
context 'with errors' do
|
||||
it "displays the errors" do
|
||||
existing_user = create(:user)
|
||||
|
||||
create(:user, email: new_user.email)
|
||||
visit new_user_registration_path
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: existing_user.email
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
click_button "Register"
|
||||
|
||||
expect(current_path).to eq user_registration_path
|
||||
|
@ -261,20 +206,10 @@ RSpec.shared_examples 'Signup' do
|
|||
end
|
||||
|
||||
it 'does not redisplay the password' do
|
||||
existing_user = create(:user)
|
||||
|
||||
create(:user, email: new_user.email)
|
||||
visit new_user_registration_path
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: existing_user.email
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
click_button "Register"
|
||||
|
||||
expect(current_path).to eq user_registration_path
|
||||
|
@ -290,18 +225,7 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'requires the user to check the checkbox' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
|
||||
fill_in_signup_form
|
||||
click_button 'Register'
|
||||
|
||||
expect(current_path).to eq new_user_session_path
|
||||
|
@ -311,19 +235,8 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'asks the user to accept terms before going to the dashboard' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
check :terms_opt_in
|
||||
|
||||
click_button "Register"
|
||||
|
||||
expect(current_path).to eq users_sign_up_welcome_path
|
||||
|
@ -353,17 +266,7 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'prevents from signing up' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
|
||||
expect { click_button 'Register' }.not_to change { User.count }
|
||||
expect(page).to have_content('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
|
||||
|
@ -374,17 +277,7 @@ RSpec.shared_examples 'Signup' do
|
|||
it 'prevents from signing up' do
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
|
||||
expect { click_button 'Register' }.not_to change { User.count }
|
||||
expect(page).to have_content('That was a bit too quick! Please resubmit.')
|
||||
|
@ -393,36 +286,27 @@ RSpec.shared_examples 'Signup' do
|
|||
end
|
||||
|
||||
it 'redirects to step 2 of the signup process, sets the role and redirects back' do
|
||||
new_user = build_stubbed(:user)
|
||||
visit new_user_registration_path
|
||||
|
||||
fill_in 'new_user_username', with: new_user.username
|
||||
fill_in 'new_user_email', with: new_user.email
|
||||
|
||||
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
|
||||
|
||||
fill_in 'new_user_password', with: new_user.password
|
||||
fill_in_signup_form
|
||||
click_button 'Register'
|
||||
|
||||
visit new_project_path
|
||||
|
||||
expect(page).to have_current_path(users_sign_up_welcome_path)
|
||||
|
||||
select 'Software Developer', from: 'user_role'
|
||||
click_button 'Get started!'
|
||||
new_user = User.find_by_username(new_user.username)
|
||||
|
||||
expect(new_user.software_developer_role?).to be_truthy
|
||||
expect(new_user.setup_for_company).to be_nil
|
||||
created_user = User.find_by_username(new_user.username)
|
||||
|
||||
expect(created_user.software_developer_role?).to be_truthy
|
||||
expect(created_user.setup_for_company).to be_nil
|
||||
expect(page).to have_current_path(new_project_path)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'Signup name validation' do |field, max_length|
|
||||
RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
|
||||
before do
|
||||
visit new_user_registration_path
|
||||
end
|
||||
|
@ -446,10 +330,10 @@ RSpec.shared_examples 'Signup name validation' do |field, max_length|
|
|||
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
|
||||
it "shows an error message if the user\'s #{label} 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).")
|
||||
expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
|
||||
end
|
||||
|
||||
it 'shows an error message if the username contains emojis' do
|
||||
|
@ -467,7 +351,8 @@ RSpec.describe 'With original flow' do
|
|||
end
|
||||
|
||||
it_behaves_like 'Signup'
|
||||
it_behaves_like 'Signup name validation', 'new_user_name', 255
|
||||
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
|
||||
it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
|
||||
end
|
||||
|
||||
RSpec.describe 'With experimental flow' do
|
||||
|
@ -477,8 +362,8 @@ RSpec.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
|
||||
it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
|
||||
it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
|
||||
|
||||
context 'when terms_opt_in experimental is enabled' do
|
||||
include TermsHelper
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const path = require('path');
|
||||
const { ErrorWithStack } = require('jest-util');
|
||||
const JSDOMEnvironment = require('jest-environment-jsdom-sixteen');
|
||||
const JSDOMEnvironment = require('jest-environment-jsdom');
|
||||
const { TEST_HOST } = require('./helpers/test_constants');
|
||||
|
||||
const ROOT_PATH = path.resolve(__dirname, '../..');
|
||||
|
|
|
@ -629,8 +629,9 @@ describe('GfmAutoComplete', () => {
|
|||
let $textarea;
|
||||
|
||||
beforeEach(() => {
|
||||
setFixtures('<textarea></textarea>');
|
||||
autocomplete = new GfmAutoComplete(dataSources);
|
||||
$textarea = $('<textarea></textarea>');
|
||||
$textarea = $('textarea');
|
||||
autocomplete.setup($textarea, { labels: true });
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('DropdownSearchInputComponent', () => {
|
|||
});
|
||||
|
||||
it('renders search icon element', () => {
|
||||
expect(wrapper.find('.fa-search.dropdown-input-search').exists()).toBe(true);
|
||||
expect(wrapper.find('.dropdown-input-search[data-testid="search-icon"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays custom placeholder text', () => {
|
||||
|
|
|
@ -51,6 +51,11 @@ RSpec.describe Gitlab::Git::Wiki do
|
|||
expect(subject.page(title: 'page1', dir: '').url_path).to eq 'page1'
|
||||
expect(subject.page(title: 'page1', dir: 'foo').url_path).to eq 'foo/page1'
|
||||
end
|
||||
|
||||
it 'returns nil for invalid arguments' do
|
||||
expect(subject.page(title: '')).to be_nil
|
||||
expect(subject.page(title: 'foo', version: ':')).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete_page' do
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'rubocop'
|
||||
require 'rubocop/rspec/support'
|
||||
|
||||
require_relative '../../../../rubocop/cop/rspec/expect_gitlab_tracking'
|
||||
|
||||
RSpec.describe RuboCop::Cop::RSpec::ExpectGitlabTracking do
|
||||
include CopHelper
|
||||
|
||||
let(:source_file) { 'spec/foo_spec.rb' }
|
||||
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
good_samples = [
|
||||
'expect_snowplow_event(category: nil, action: nil)',
|
||||
'expect_snowplow_event(category: "EventCategory", action: "event_action")',
|
||||
'expect_snowplow_event(category: "EventCategory", action: "event_action", label: "label", property: "property")',
|
||||
'expect_no_snowplow_event'
|
||||
]
|
||||
|
||||
bad_samples = [
|
||||
'expect(Gitlab::Tracking).to receive(:event)',
|
||||
'expect(Gitlab::Tracking).to_not receive(:event)',
|
||||
'expect(Gitlab::Tracking).not_to receive(:event)',
|
||||
'expect(Gitlab::Tracking).to_not receive(:event).with("EventCategory", "event_action")',
|
||||
'expect(Gitlab::Tracking).not_to receive(:event).with("EventCategory", "event_action")',
|
||||
'expect(Gitlab::Tracking).to receive(:event).with("EventCategory", "event_action", label: "label", property: "property")',
|
||||
'expect(Gitlab::Tracking).to have_received(:event).with("EventCategory", "event_action")',
|
||||
'expect(Gitlab::Tracking).to_not have_received(:event).with("EventCategory", "event_action")',
|
||||
'expect(Gitlab::Tracking).not_to have_received(:event).with("EventCategory", "event_action")',
|
||||
'allow(Gitlab::Tracking).to receive(:event).and_call_original'
|
||||
]
|
||||
|
||||
good_samples.each do |good|
|
||||
context "good: #{good}" do
|
||||
it 'does not register an offense' do
|
||||
inspect_source(good)
|
||||
|
||||
expect(cop.offenses).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
bad_samples.each do |bad|
|
||||
context "bad: #{bad}" do
|
||||
it 'registers an offense', :aggregate_failures do
|
||||
inspect_source(bad, source_file)
|
||||
|
||||
expect(cop.offenses.size).to eq(1)
|
||||
expect(cop.offenses.map(&:line)).to eq([1])
|
||||
expect(cop.highlights).to eq([bad])
|
||||
|
||||
msg = cop.offenses.first.message
|
||||
|
||||
expect(msg).to match(
|
||||
/Do not expect directly on `Gitlab::Tracking#event`/
|
||||
)
|
||||
expect(msg).to match(/add the `snowplow` annotation/)
|
||||
expect(msg).to match(/use `expect_snowplow_event` instead/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -46,7 +46,8 @@ RSpec.describe Ci::RetryBuildService do
|
|||
job_variables waiting_for_resource_at job_artifacts_metrics_referee
|
||||
job_artifacts_network_referee job_artifacts_dotenv
|
||||
job_artifacts_cobertura needs job_artifacts_accessibility
|
||||
job_artifacts_requirements job_artifacts_coverage_fuzzing].freeze
|
||||
job_artifacts_requirements job_artifacts_coverage_fuzzing
|
||||
job_artifacts_api_fuzzing].freeze
|
||||
|
||||
ignore_accessors =
|
||||
%i[type lock_version target_url base_tags trace_sections
|
||||
|
|
|
@ -4,11 +4,11 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Users::BuildService do
|
||||
describe '#execute' do
|
||||
let(:params) do
|
||||
{ name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' }
|
||||
end
|
||||
let(:params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) }
|
||||
|
||||
context 'with an admin user' do
|
||||
let(:params) { build_stubbed(:user).slice(:name, :username, :email, :password) }
|
||||
|
||||
let(:admin_user) { create(:admin) }
|
||||
let(:service) { described_class.new(admin_user, ActionController::Parameters.new(params).permit!) }
|
||||
|
||||
|
|
|
@ -282,8 +282,9 @@ RSpec.shared_examples 'wiki model' do
|
|||
expect(page.title).to eq('index page')
|
||||
end
|
||||
|
||||
it 'returns nil if the page does not exist' do
|
||||
expect(subject.find_page('non-existent')).to eq(nil)
|
||||
it 'returns nil if the page or version does not exist' do
|
||||
expect(subject.find_page('non-existent')).to be_nil
|
||||
expect(subject.find_page('index page', 'non-existent')).to be_nil
|
||||
end
|
||||
|
||||
it 'can find a page by slug' do
|
||||
|
|
Loading…
Reference in New Issue