Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-08-06 00:09:08 +00:00
parent b54ba745ea
commit 1acb6e46fe
47 changed files with 778 additions and 415 deletions

View file

@ -493,7 +493,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/ci/unit_test_reports.md @marcel.amirault
/doc/ci/variables/ @marcel.amirault
/doc/ci/yaml/ @marcel.amirault
/doc/development/adding_database_indexes.md @aqualls
/doc/development/application_limits.md @axil
/doc/development/approval_rules.md @aqualls
/doc/development/audit_event_guide/index.md @eread
@ -512,12 +511,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/code_intelligence/index.md @aqualls
/doc/development/contributing/ @sselhorn
/doc/development/contributing/merge_request_workflow.md @aqualls
/doc/development/creating_enums.md @aqualls
/doc/development/database_debugging.md @aqualls
/doc/development/database_query_comments.md @aqualls
/doc/development/database_review.md @aqualls
/doc/development/database/ @aqualls
/doc/development/db_dump.md @aqualls
/doc/development/developing_with_solargraph.md @aqualls
/doc/development/diffs.md @aqualls
/doc/development/distributed_tracing.md @msedlakjakubowski
@ -538,7 +533,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/feature_flags/controls.md @sselhorn
/doc/development/feature_flags/index.md @sselhorn
/doc/development/filtering_by_label.md @msedlakjakubowski
/doc/development/foreign_keys.md @aqualls
/doc/development/geo.md @axil
/doc/development/geo/framework.md @axil
/doc/development/git_object_deduplication.md @eread
@ -552,7 +546,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/image_scaling.md @sselhorn
/doc/development/import_export.md @eread
/doc/development/index.md @sselhorn
/doc/development/insert_into_tables_in_batches.md @aqualls
/doc/development/integrations/ @kpaizee
/doc/development/integrations/codesandbox.md @sselhorn
/doc/development/integrations/secure_partner_integration.md @rdickenson
@ -561,7 +554,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/internal_users.md @sselhorn
/doc/development/issuable-like-models.md @msedlakjakubowski
/doc/development/issue_types.md @msedlakjakubowski
/doc/development/iterating_tables_in_batches.md @aqualls
/doc/development/kubernetes.md @sselhorn
/doc/development/lfs.md @aqualls
/doc/development/ee_features.md @fneill
@ -570,30 +562,22 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/new_fe_guide/modules/widget_extensions.md @aqualls
/doc/development/new_fe_guide/tips.md @sselhorn
/doc/development/omnibus.md @axil
/doc/development/ordering_table_columns.md @aqualls
/doc/development/packages/ @claytoncornell
/doc/development/permissions.md @eread
/doc/development/policies.md @eread
/doc/development/product_qualified_lead_guide/index.md @kpaizee
/doc/development/project_templates.md @fneill
/doc/development/prometheus_metrics.md @msedlakjakubowski
/doc/development/query_performance.md @aqualls
/doc/development/query_recorder.md @aqualls
/doc/development/real_time.md @msedlakjakubowski
/doc/development/secure_coding_guidelines.md @sselhorn
/doc/development/serializing_data.md @aqualls
/doc/development/service_ping/ @claytoncornell
/doc/development/single_table_inheritance.md @aqualls
/doc/development/snowplow/ @claytoncornell
/doc/development/spam_protection_and_captcha/ @eread
/doc/development/sql.md @aqualls
/doc/development/swapping_tables.md @aqualls
/doc/development/testing_guide/best_practices.md @sselhorn
/doc/development/testing_guide/end_to_end/best_practices.md @sselhorn
/doc/development/understanding_explain_plans.md @aqualls
/doc/development/value_stream_analytics.md @fneill
/doc/development/value_stream_analytics/value_stream_analytics_aggregated_backend.md @fneill
/doc/development/verifying_database_capabilities.md @aqualls
/doc/development/wikis.md @aqualls
/doc/development/work_items_widgets.md @msedlakjakubowski
/doc/development/work_items.md @msedlakjakubowski

View file

@ -84,89 +84,6 @@
border-bottom: 1px solid $white-dark;
padding: 11px 0;
margin-bottom: 11px;
&.no-bottom-space {
border-bottom: 0;
margin-bottom: 0;
}
}
.cover-block {
text-align: center;
background: $gray-light;
padding-top: 44px;
position: relative;
.avatar-holder {
.avatar,
.identicon {
margin: 0 auto;
float: none;
}
.identicon {
border-radius: 50%;
}
}
.cover-title {
color: $gl-text-color;
font-size: 23px;
h1 {
color: $gl-text-color;
margin-bottom: 6px;
font-size: 23px;
}
.visibility-icon {
display: inline-block;
margin-left: 5px;
font-size: 18px;
color: color('gray');
}
p {
padding: 0 $gl-padding;
color: $gl-text-color;
}
}
.cover-controls {
@include media-breakpoint-up(sm) {
position: absolute;
top: 1rem;
right: 1.25rem;
}
&.left {
@include media-breakpoint-up(sm) {
left: 1.25rem;
right: auto;
}
}
}
&.user-cover-block {
padding: 24px 0 0;
.nav-links {
width: 100%;
float: none;
&.scrolling-tabs {
float: none;
}
}
li:first-child {
margin-left: auto;
}
li:last-child {
margin-right: auto;
}
}
}
.content-block {

View file

@ -1,30 +1,3 @@
.calendar-block {
padding-left: 0;
padding-right: 0;
border-top: 0;
@media (min-width: map-get($grid-breakpoints, sm)) and (max-width: map-get($grid-breakpoints, sm)) {
overflow-x: auto;
}
}
.user-calendar-activities {
direction: ltr;
.str-truncated {
max-width: 70%;
}
}
.user-calendar {
text-align: center;
min-height: 172px;
.calendar {
display: inline-block;
}
}
.user-contrib-cell {
&:hover {
cursor: pointer;
@ -42,18 +15,6 @@
}
}
.user-contrib-text {
font-size: 12px;
fill: $calendar-user-contrib-text;
}
.calendar-hint {
font-size: 12px;
direction: ltr;
margin-top: -23px;
float: right;
}
.pika-single.gitlab-theme {
.pika-label {
color: $gl-text-color-secondary;

View file

@ -0,0 +1,212 @@
@import 'mixins_and_variables_and_functions';
.calendar-block {
padding-left: 0;
padding-right: 0;
border-top: 0;
@media (min-width: map-get($grid-breakpoints, sm)) and (max-width: map-get($grid-breakpoints, sm)) {
overflow-x: auto;
}
}
.calendar-hint {
font-size: 12px;
direction: ltr;
margin-top: -23px;
float: right;
}
.cover-block {
text-align: center;
background: var(--gray-50, $gray-light);
padding-top: 44px;
position: relative;
.avatar-holder {
.avatar,
.identicon {
margin: 0 auto;
float: none;
}
.identicon {
border-radius: 50%;
}
}
.cover-title {
color: var(--gl-text-color, $gl-text-color);
font-size: 23px;
h1 {
color: var(--gl-text-color, $gl-text-color);
margin-bottom: 6px;
font-size: 23px;
}
.visibility-icon {
display: inline-block;
margin-left: 5px;
font-size: 18px;
color: color('gray');
}
p {
padding: 0 $gl-padding;
color: var(--gl-text-color, $gl-text-color);
}
}
.cover-controls {
@include media-breakpoint-up(sm) {
position: absolute;
top: 1rem;
right: 1.25rem;
}
&.left {
@include media-breakpoint-up(sm) {
left: 1.25rem;
right: auto;
}
}
}
&.user-cover-block {
padding: 24px 0 0;
.nav-links {
width: 100%;
float: none;
&.scrolling-tabs {
float: none;
}
}
li:first-child {
margin-left: auto;
}
li:last-child {
margin-right: auto;
}
}
}
// Middle dot divider between each element in a list of items.
.middle-dot-divider {
@include middle-dot-divider;
}
.middle-dot-divider-sm {
@include media-breakpoint-up(sm) {
@include middle-dot-divider;
}
}
.profile-user-bio {
// Limits the width of the user bio for readability.
max-width: 600px;
margin: 10px auto;
}
.user-calendar {
text-align: center;
min-height: 172px;
.calendar {
display: inline-block;
}
}
.user-calendar-activities {
direction: ltr;
.str-truncated {
max-width: 70%;
}
}
.user-contrib-text {
font-size: 12px;
fill: $calendar-user-contrib-text;
}
.user-profile {
.profile-header {
margin: 0 $gl-padding;
&.with-no-profile-tabs {
margin-bottom: $gl-padding-24;
}
.avatar-holder {
width: 90px;
margin: 0 auto 10px;
}
}
.user-profile-nav {
font-size: 0;
}
.fade-right {
right: 0;
}
.fade-left {
left: 0;
}
.activities-block {
.event-item {
padding-left: 40px;
}
.gl-label-scoped {
--label-inset-border: inset 0 0 0 1px currentColor;
}
@include media-breakpoint-up(lg) {
margin-right: 5px;
}
}
.projects-block {
@include media-breakpoint-up(lg) {
margin-left: 5px;
}
}
@include media-breakpoint-down(xs) {
.cover-block {
padding-top: 20px;
}
.user-profile-nav {
a {
margin-right: 0;
}
}
.activities-block {
.event-item {
padding-left: 0;
}
}
}
}
.linkedin-icon {
color: $linkedin;
}
.skype-icon {
color: $skype;
}
.twitter-icon {
color: $twitter;
}

View file

@ -29,23 +29,6 @@
}
}
// Middle dot divider between each element in a list of items.
.middle-dot-divider {
@include middle-dot-divider;
}
.middle-dot-divider-sm {
@include media-breakpoint-up(sm) {
@include middle-dot-divider;
}
}
.profile-user-bio {
// Limits the width of the user bio for readability.
max-width: 600px;
margin: 10px auto;
}
.user-avatar-button {
.file-name {
display: inline-block;
@ -156,71 +139,6 @@
}
}
.user-profile {
.profile-header {
margin: 0 $gl-padding;
&.with-no-profile-tabs {
margin-bottom: $gl-padding-24;
}
.avatar-holder {
width: 90px;
margin: 0 auto 10px;
}
}
.user-profile-nav {
font-size: 0;
}
.fade-right {
right: 0;
}
.fade-left {
left: 0;
}
.activities-block {
.event-item {
padding-left: 40px;
}
.gl-label-scoped {
--label-inset-border: inset 0 0 0 1px currentColor;
}
@include media-breakpoint-up(lg) {
margin-right: 5px;
}
}
.projects-block {
@include media-breakpoint-up(lg) {
margin-left: 5px;
}
}
@include media-breakpoint-down(xs) {
.cover-block {
padding-top: 20px;
}
.user-profile-nav {
a {
margin-right: 0;
}
}
.activities-block {
.event-item {
padding-left: 0;
}
}
}
}
table.u2f-registrations {
th:not(:last-child),
td:not(:last-child) {
@ -366,15 +284,3 @@ table.u2f-registrations {
.gitlab-slack-slack-logo {
transform: scale(200%); // Slack logo SVG is scaled down 50% and has empty space around it
}
.skype-icon {
color: $skype;
}
.linkedin-icon {
color: $linkedin;
}
.twitter-icon {
color: $twitter;
}

View file

@ -1,7 +1,10 @@
# frozen_string_literal: true
# Renders a Pajamas compliant checkbox element
# Must be used in an instance of `ActionView::Helpers::FormBuilder`
# An instance of `ActionView::Helpers::FormBuilder` must be passed as the `form` argument.
# The easiest way to use this component is by using the `gitlab_ui_checkbox_component` helper.
# See https://docs.gitlab.com/ee/development/fe_guide/haml.html#gitlab_ui_checkbox_component
# To use a checkbox without an instance of `ActionView::Helpers::FormBuilder` use `CheckboxTagComponent`.
module Pajamas
class CheckboxComponent < Pajamas::Component
include Pajamas::Concerns::CheckboxRadioLabelWithHelpText
@ -31,6 +34,8 @@ module Pajamas
@value = checked_value if checkbox_options[:multiple]
end
private
attr_reader(
:form,
:method,
@ -43,8 +48,6 @@ module Pajamas
:value
)
private
def label_content
label? ? label : label_argument
end

View file

@ -0,0 +1,6 @@
.gl-form-checkbox.custom-control.custom-checkbox
= check_box_tag(name,
value,
checked,
formatted_input_options)
= render_label_tag_with_help_text

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
# Renders a Pajamas compliant checkbox element
module Pajamas
class CheckboxTagComponent < Pajamas::Component
include Pajamas::Concerns::CheckboxRadioLabelWithHelpText
include Pajamas::Concerns::CheckboxRadioOptions
renders_one :label
renders_one :help_text
def initialize(
name:,
label_options: {},
checkbox_options: {},
value: '1',
checked: false
)
@name = name
@label_options = label_options
@input_options = checkbox_options
@value = value
@checked = checked
end
private
attr_reader(
:name,
:label_options,
:input_options,
:value,
:checked
)
def label_content
label
end
def help_text_content
help_text
end
end
end

View file

@ -7,6 +7,10 @@ module Pajamas
form.label(method, formatted_label_options) { label_entry }
end
def render_label_tag_with_help_text
label_tag(name, formatted_label_options) { label_entry }
end
private
def label_entry

View file

@ -28,6 +28,8 @@ module Pajamas
@value = value
end
private
attr_reader(
:form,
:method,
@ -38,8 +40,6 @@ module Pajamas
:value
)
private
def label_content
label? ? label : label_argument
end

View file

@ -20,7 +20,7 @@ module Ci
private
def upgrade_check_service
Gitlab::Ci::RunnerUpgradeCheck.instance
@runner_upgrade_check ||= Gitlab::Ci::RunnerUpgradeCheck.new(::Gitlab::VERSION)
end
end
end

View file

@ -22,7 +22,7 @@ module Ci
private
def upgrade_check
Gitlab::Ci::RunnerUpgradeCheck.instance
@runner_upgrade_check ||= Gitlab::Ci::RunnerUpgradeCheck.new(::Gitlab::VERSION)
end
# rubocop: disable CodeReuse/ActiveRecord

View file

@ -25,9 +25,9 @@ module MergeRequests
)
else
create_event(merge_request)
stream_audit_event(merge_request)
end
stream_audit_event(merge_request)
create_approval_note(merge_request)
mark_pending_todos_as_done(merge_request)
execute_approval_hooks(merge_request, current_user)

View file

@ -63,18 +63,20 @@
= s_('ProjectsNew|Project Configuration')
.form-group
.form-check.gl-mb-3
= check_box_tag 'project[initialize_with_readme]', '1', true, class: 'form-check-input', data: { qa_selector: 'initialize_with_readme_checkbox', track_label: track_label, track_action: 'activate_form_input', track_property: 'init_with_readme' }
= label_tag 'project[initialize_with_readme]', s_('ProjectsNew|Initialize repository with a README'), class: 'form-check-label'
.form-text.text-muted
= render Pajamas::CheckboxTagComponent.new(name: 'project[initialize_with_readme]',
checked: true,
checkbox_options: { data: { qa_selector: 'initialize_with_readme_checkbox', track_label: track_label, track_action: 'activate_form_input', track_property: 'init_with_readme' } }) do |c|
= c.label do
= s_('ProjectsNew|Initialize repository with a README')
= c.help_text do
= s_('ProjectsNew|Allows you to immediately clone this projects repository. Skip this if you plan to push up an existing repository.')
.form-group
.form-check.gl-mb-3
= check_box_tag 'project[initialize_with_sast]', '1', false, class: 'form-check-input', data: { qa_selector: 'initialize_with_sast_checkbox', track_label: track_label, track_action: 'activate_form_input', track_property: 'init_with_sast' }
= label_tag 'project[initialize_with_sast]', class: 'form-check-label' do
= render Pajamas::CheckboxTagComponent.new(name: 'project[initialize_with_sast]',
checkbox_options: { data: { qa_selector: 'initialize_with_sast_checkbox', track_label: track_label, track_action: 'activate_form_input', track_property: 'init_with_sast' } }) do |c|
= c.label do
= s_('ProjectsNew|Enable Static Application Security Testing (SAST)')
.form-text.text-muted
= c.help_text do
= s_('ProjectsNew|Analyze your source code for known security vulnerabilities.')
= link_to _('Learn more.'), help_page_path('user/application_security/sast/index'), target: '_blank', rel: 'noopener noreferrer', data: { track_action: 'followed' }

View file

@ -1,7 +1,7 @@
- add_to_breadcrumbs _("Compare Revisions"), project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}"
.sub-header-block.no-bottom-space
.sub-header-block.gl-border-b-0.gl-mb-0
.js-signature-container{ data: { 'signatures-path' => signatures_namespace_project_compare_index_path } }
#js-compare-selector{ data: project_compare_selector_data(@project, @merge_request, params) }

View file

@ -4,6 +4,7 @@
- page_title user_display_name(@user)
- page_description @user.bio unless @user.blocked? || !@user.confirmed?
- page_itemtype 'http://schema.org/Person'
- add_page_specific_style 'page_bundles/profile'
- link_classes = "flex-grow-1 mx-1 "
= content_for :meta_tags do

View file

@ -290,6 +290,7 @@ module Gitlab
config.assets.precompile << "page_bundles/pipelines.css"
config.assets.precompile << "page_bundles/pipeline_editor.css"
config.assets.precompile << "page_bundles/productivity_analytics.css"
config.assets.precompile << "page_bundles/profile.css"
config.assets.precompile << "page_bundles/profile_two_factor_auth.css"
config.assets.precompile << "page_bundles/project.css"
config.assets.precompile << "page_bundles/projects_edit.css"

View file

@ -1,8 +0,0 @@
---
name: incremental_repository_backup
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79589
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/355945
milestone: '14.9'
type: development
group: group::gitaly
default_enabled: true

View file

@ -287,6 +287,8 @@
- 1
- - merge_requests_resolve_todos
- 1
- - merge_requests_stream_approval_audit_event
- 1
- - merge_requests_sync_code_owner_approval_rules
- 1
- - merge_requests_update_head_pipeline

View file

@ -153,6 +153,39 @@ If you want to add custom attributes to any of these or the card itself, use the
For the full list of options, see its
[source](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/components/pajamas/card_component.rb).
#### Checkbox tag
The `Pajamas::CheckboxTagComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox) specification.
The `name` argument and `label` slot are required.
For example:
```haml
= render Pajamas::CheckboxTagComponent.new(name: 'project[initialize_with_sast]',
checkbox_options: { data: { qa_selector: 'initialize_with_sast_checkbox', track_label: track_label, track_action: 'activate_form_input', track_property: 'init_with_sast' } }) do |c|
= c.label do
= s_('ProjectsNew|Enable Static Application Security Testing (SAST)')
= c.help_text do
= s_('ProjectsNew|Analyze your source code for known security vulnerabilities.')
= link_to _('Learn more.'), help_page_path('user/application_security/sast/index'), target: '_blank', rel: 'noopener noreferrer', data: { track_action: 'followed' }
```
For the full list of options, see its
[source](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/components/pajamas/checkbox_tag_component.rb).
#### Checkbox
The `Pajamas::CheckboxComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox) specification.
NOTE:
`Pajamas::CheckboxComponent` is used internally by the [GitLab UI form builder](haml.md#use-the-gitlab-ui-form-builder) and requires an instance of [ActionView::Helpers::FormBuilder](https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html) to be passed as the `form` argument.
It is preferred to use the [gitlab_ui_checkbox_component](haml.md#gitlab_ui_checkbox_component) method to render this ViewComponent.
To use a checkbox without an instance of [ActionView::Helpers::FormBuilder](https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html) use [CheckboxTagComponent](#checkbox-tag).
For the full list of options, see its
[source](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/components/pajamas/checkbox_component.rb).
#### Toggle
The `Pajamas::ToggleComponent` follows the [Pajamas Toggle](https://design.gitlab.com/components/toggle) specification.

View file

@ -0,0 +1,11 @@
---
redirect_to: 'database/single_table_inheritance.md'
remove_date: '2022-11-06'
---
This document was moved to [another location](database/single_table_inheritance.md).
<!-- This redirect file can be deleted after <2022-11-06>. -->
<!-- Redirects that point to other docs in the same project expire in three months. -->
<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->

View file

@ -28,14 +28,14 @@ Before running the consumer tests, go to `spec/contracts/consumer` and run `npm
### Run the provider tests
Before running the provider tests, make sure your GDK (GitLab Development Kit) is fully set up and running. You can follow the setup instructions detailed in the [GDK repository](https://gitlab.com/gitlab-org/gitlab-development-kit/-/tree/main). To run the provider tests, you use Rake tasks that are defined in [`./lib/tasks/contracts.rake`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/tasks/contracts.rake). To get a list of all the Rake tasks related to the provider tests, run `bundle exec rake -T contracts`. For example:
Before running the provider tests, make sure your GDK (GitLab Development Kit) is fully set up and running. You can follow the setup instructions detailed in the [GDK repository](https://gitlab.com/gitlab-org/gitlab-development-kit/-/tree/main). To run the provider tests, you use Rake tasks that can be found in [`./lib/tasks/contracts`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/tasks/contracts). To get a list of all the Rake tasks related to the provider tests, run `bundle exec rake -T contracts`. For example:
```shell
$ bundle exec rake -T contracts
rake contracts:mr:pact:verify:diffs # Verify provider against the consumer pacts for diffs
rake contracts:mr:pact:verify:discussions # Verify provider against the consumer pacts for discussions
rake contracts:mr:pact:verify:metadata # Verify provider against the consumer pacts for metadata
rake contracts:mr:test:merge_request[contract_mr] # Run all merge request contract tests
rake contracts:merge_requests:pact:verify:diffs_batch # Verify provider against the consumer pacts for diffs_batch
rake contracts:merge_requests:pact:verify:diffs_metadata # Verify provider against the consumer pacts for diffs_metadata
rake contracts:merge_requests:pact:verify:discussions # Verify provider against the consumer pacts for discussions
rake contracts:merge_requests:test:merge_requests[contract_merge_requests] # Run all merge request contract tests
```
## Test suite folder structure and naming conventions

View file

@ -32,16 +32,13 @@ module Backup
raise Error, "unknown backup type: #{type}"
end
args = []
args = ['-layout', 'pointer']
args += ['-parallel', @max_parallelism.to_s] if @max_parallelism
args += ['-parallel-storage', @storage_parallelism.to_s] if @storage_parallelism
if Feature.enabled?(:incremental_repository_backup)
args += ['-layout', 'pointer']
if type == :create
args += ['-incremental'] if incremental?
args += ['-id', backup_id] if backup_id
end
end
@input_stream, stdout, @thread = Open3.popen2(build_env, bin_path, command, '-path', backup_repos_path, *args)

View file

@ -34,11 +34,7 @@ module Backup
def initialize(progress, definitions: nil)
@progress = progress
@incremental = Feature.feature_flags_available? &&
Feature.enabled?(:incremental_repository_backup) &&
Gitlab::Utils.to_boolean(ENV['INCREMENTAL'], default: false)
@incremental = Gitlab::Utils.to_boolean(ENV['INCREMENTAL'], default: false)
@definitions = definitions
end

View file

@ -74,7 +74,7 @@ module Gitlab
releases = response.parsed_response
.map { |release| parse_runner_release(release) }
.select(&:valid?)
.sort!
.sort
return if releases.empty? && response.parsed_response.present?

View file

@ -3,7 +3,10 @@
module Gitlab
module Ci
class RunnerUpgradeCheck
include Singleton
def initialize(gitlab_version, runner_releases_store = nil)
@gitlab_version = ::Gitlab::VersionInfo.parse(gitlab_version, parse_suffix: true)
@releases_store = runner_releases_store
end
def check_runner_upgrade_suggestion(runner_version)
check_runner_upgrade_suggestions(runner_version).first
@ -11,12 +14,8 @@ module Gitlab
private
def gitlab_version
@gitlab_version ||= ::Gitlab::VersionInfo.parse(::Gitlab::VERSION, parse_suffix: true)
end
def runner_releases_store
RunnerReleases.instance
@releases_store ||= RunnerReleases.instance
end
def add_suggestion(suggestions, runner_version, version, status)
@ -54,12 +53,12 @@ module Gitlab
# Consider the edge case of pre-release runner versions that get registered, but are never published.
# In this case, suggest the latest compatible runner version
latest_release = runner_releases_store.releases_by_minor.values.select { |v| v < gitlab_version }.max
latest_release = runner_releases_store.releases_by_minor.values.select { |v| v < @gitlab_version }.max
add_suggestion(suggestions, runner_version, latest_release, :recommended)
end
def add_available_runner_release(runner_version, suggestions)
available_version = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
available_version = runner_releases_store.releases_by_minor[@gitlab_version.without_patch]
unless suggestions.include?(available_version)
add_suggestion(suggestions, runner_version, available_version, :available)
end
@ -76,12 +75,12 @@ module Gitlab
outside_window = minor_releases_with_index.count - runner_minor_version_index > 3
if outside_window
recommended_version = runner_releases_store.releases_by_minor[gitlab_version.without_patch]
recommended_version = runner_releases_store.releases_by_minor[@gitlab_version.without_patch]
return add_suggestion(suggestions, runner_version, recommended_version, :recommended)
end
else
# If unknown runner version, then recommend the latest version for the GitLab instance
return add_recommended_runner_release_update(gitlab_version, suggestions)
return add_recommended_runner_release_update(@gitlab_version, suggestions)
end
false

View file

@ -33,9 +33,9 @@ namespace :contracts do
end
desc 'Run all merge request contract tests'
task 'test:merge_requests', :contract_mr do |_t, arg|
task 'test:merge_requests', :contract_merge_requests do |_t, arg|
errors = %w[diffs_batch diffs_metadata discussions].each_with_object([]) do |task, err|
Rake::Task["contracts:mr:pact:verify:#{task}"].execute
Rake::Task["contracts:merge_requests:pact:verify:#{task}"].execute
rescue StandardError, SystemExit
err << "contracts:merge_requests:pact:verify:#{task}"
end

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
return if Rails.env.production?
require 'pact/tasks/verification_task'
contracts = File.expand_path('../../../spec/contracts/contracts/project/pipeline_schedule', __dir__)
provider = File.expand_path('../../../provider', contracts)
# rubocop:disable Rails/RakeEnvironment
namespace :contracts do
namespace :pipeline_schedules do
Pact::VerificationTask.new(:update_pipeline_schedule) do |pact|
pact.uri(
"#{contracts}/edit/pipelineschedules#edit-put_edit_a_pipeline_schedule.json",
pact_helper: "#{provider}/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb"
)
end
desc 'Run all pipeline schedule contract tests'
task 'test:pipeline_schedules', :contract_pipeline_schedules do |_t, arg|
errors = %w[
update_pipeline_schedule
].each_with_object([]) do |task, err|
Rake::Task["contracts:pipeline_schedules:pact:verify:#{task}"].execute
rescue StandardError, SystemExit
err << "contracts:pipeline_schedule:pact:verify:#{task}"
end
raise StandardError, "Errors in tasks #{errors.join(', ')}" unless errors.empty?
end
end
end
# rubocop:enable Rails/RakeEnvironment

View file

@ -39,7 +39,7 @@ namespace :contracts do
end
desc 'Run all pipeline contract tests'
task 'test:pipelines', :contract_mr do |_t, arg|
task 'test:pipelines', :contract_pipelines do |_t, arg|
errors = %w[
create_a_new_pipeline
get_list_project_pipelines

View file

@ -8,12 +8,6 @@ RSpec.describe Pajamas::CheckboxComponent, :aggregate_failures, type: :component
let_it_be(:label) { "Show one file at a time on merge request's Changes tab" }
let_it_be(:help_text) { 'Instead of all the files changed, show only one file at a time.' }
RSpec.shared_examples 'it renders unchecked checkbox with value of `1`' do
it 'renders unchecked checkbox with value of `1`' do
expect(page).to have_unchecked_field(label, with: '1')
end
end
context 'with default options' do
before do
fake_form_for do |form|

View file

@ -0,0 +1,59 @@
# frozen_string_literal: true
require "spec_helper"
RSpec.describe Pajamas::CheckboxTagComponent, :aggregate_failures, type: :component do
let_it_be(:name) { :view_diffs_file_by_file }
let_it_be(:label) { "Show one file at a time on merge request's Changes tab" }
let_it_be(:help_text) { 'Instead of all the files changed, show only one file at a time.' }
context 'with default options' do
before do
render_inline(described_class.new(name: name)) do |c|
c.label { label }
end
end
include_examples 'it renders unchecked checkbox with value of `1`'
include_examples 'it does not render help text'
end
context 'with custom options' do
let_it_be(:value) { 'yes' }
let_it_be(:checkbox_options) { { class: 'checkbox-foo-bar', checked: true } }
let_it_be(:label_options) { { class: 'label-foo-bar' } }
before do
render_inline(
described_class.new(
name: name,
value: value,
checked: true,
checkbox_options: checkbox_options,
label_options: label_options
)
) do |c|
c.label { label }
end
end
it 'renders checked checkbox with value of `yes`' do
expect(page).to have_checked_field(label, with: value, class: checkbox_options[:class])
end
it 'adds CSS class to label' do
expect(page).to have_selector('label.label-foo-bar')
end
end
context 'with `help_text` slot' do
before do
render_inline(described_class.new(name: name)) do |c|
c.label { label }
c.help_text { help_text }
end
end
include_examples 'it renders unchecked checkbox with value of `1`'
include_examples 'it renders help text'
end
end

View file

@ -8,6 +8,7 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
attr_reader(
:form,
:method,
:name,
:label_argument,
:help_text_argument,
:label_options,
@ -16,8 +17,9 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
)
def initialize(
form:,
method:,
form: nil,
method: nil,
name: nil,
label: nil,
help_text: nil,
label_options: {},
@ -26,6 +28,7 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
)
@form = form
@method = method
@name = name
@label_argument = label
@help_text_argument = help_text
@label_options = label_options
@ -46,19 +49,25 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
end
include Pajamas::Concerns::CheckboxRadioLabelWithHelpText
include ActionView::Context
include ActionView::Helpers::TagHelper
include ActionView::Helpers::FormTagHelper
end
end
let_it_be(:method) { 'username' }
let_it_be(:method_or_name) { 'username' }
let_it_be(:label_options) { { class: 'foo-bar' } }
let_it_be(:value) { 'Foo bar' }
let_it_be(:expected_label_entry) { '<span>Label argument</span>' }
let_it_be(:expected_label_with_help_text_entry) do
'<span>Label argument</span><p class="help-text" data-testid="pajamas-component-help-text">Help text argument</p>'
end
describe '#render_label_with_help_text' do
it 'calls `#format_options` with correct arguments' do
allow(form).to receive(:label)
component = component_class.new(form: form, method: method, label_options: label_options, value: value)
component = component_class.new(form: form, method: method_or_name, label_options: label_options, value: value)
expect(component).to receive(:format_options).with(
options: label_options,
@ -73,16 +82,13 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
it 'calls `form.label` with `label` and `help_text` arguments used in the block' do
component = component_class.new(
form: form,
method: method,
method: method_or_name,
label: 'Label argument',
help_text: 'Help text argument'
)
expected_label_entry = '<span>Label argument</span><p class="help-text"' \
' data-testid="pajamas-component-help-text">Help text argument</p>'
expect(form).to receive(:label).with(method, {}) do |&block|
expect(block.call).to eq(expected_label_entry)
expect(form).to receive(:label).with(method_or_name, {}) do |&block|
expect(block.call).to eq(expected_label_with_help_text_entry)
end
component.render_label_with_help_text
@ -93,13 +99,11 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
it 'calls `form.label` with `label` argument used in the block' do
component = component_class.new(
form: form,
method: method,
method: method_or_name,
label: 'Label argument'
)
expected_label_entry = '<span>Label argument</span>'
expect(form).to receive(:label).with(method, {}) do |&block|
expect(form).to receive(:label).with(method_or_name, {}) do |&block|
expect(block.call).to eq(expected_label_entry)
end
@ -107,4 +111,49 @@ RSpec.describe Pajamas::Concerns::CheckboxRadioLabelWithHelpText do
end
end
end
describe '#render_label_tag_with_help_text' do
it 'calls `#format_options` with correct arguments' do
component = component_class.new(name: method_or_name, label_options: label_options, value: value)
expect(component).to receive(:format_options).with(
options: label_options,
css_classes: ['custom-control-label'],
additional_options: { value: value }
)
component.render_label_tag_with_help_text
end
context 'when `help_text` argument is passed' do
it 'calls `label_tag` with `label` and `help_text` arguments used in the block' do
component = component_class.new(
name: method_or_name,
label: 'Label argument',
help_text: 'Help text argument'
)
expect(component).to receive(:label_tag).with(method_or_name, {}) do |&block|
expect(block.call).to eq(expected_label_with_help_text_entry)
end
component.render_label_tag_with_help_text
end
end
context 'when `help_text` argument is not passed' do
it 'calls `label_tag` with `label` argument used in the block' do
component = component_class.new(
name: method_or_name,
label: 'Label argument'
)
expect(component).to receive(:label_tag).with(method_or_name, {}) do |&block|
expect(block.call).to eq(expected_label_entry)
end
component.render_label_tag_with_help_text
end
end
end
end

View file

@ -0,0 +1,48 @@
/* eslint-disable @gitlab/require-i18n-strings */
import { Matchers } from '@pact-foundation/pact';
import { REDIRECT_HTML } from '../../../helpers/common_regex_patterns';
const body = Matchers.term({
matcher: REDIRECT_HTML,
generate:
'<html><body>You are being <a href="http://example.org/gitlab-org/gitlab-qa/-/pipelines/5">redirected</a>.</body></html>',
});
const UpdatePipelineSchedule = {
success: {
status: 302,
headers: {
'Content-Type': 'text/html; charset=utf-8',
},
body,
},
scenario: {
state: 'a project with a pipeline schedule exists',
uponReceiving: 'a request to edit a pipeline schedule',
},
request: {
withRequest: {
method: 'PUT',
path: '/gitlab-org/gitlab-qa/-/pipeline_schedules/25',
headers: {
Accept: '*/*',
'Content-Type': 'application/json; charset=utf-8',
},
body: {
schedule: {
description: 'bar',
cron: '0 1 * * *',
cron_timezone: 'UTC',
active: true,
},
},
},
},
};
export { UpdatePipelineSchedule };
/* eslint-enable @gitlab/require-i18n-strings */

View file

@ -3,7 +3,7 @@
*/
export const URL = '^(http|https)://[a-z0-9]+([-.]{1}[a-z0-9]+)*.[a-z]{2,5}(:[0-9]{1,5})?(/.*)?$';
export const URL_PATH = '^/[a-zA-Z0-9#-=?_]+$';
export const REDIRECT_HTML = 'You are being <a href=\\"(.)+/pipelines/[0-9]+\\">redirected</a>.';
export const REDIRECT_HTML = 'You are being <a href=\\"(.)+\\">redirected</a>.';
// Pipelines
export const PIPELINE_GROUPS =

View file

@ -0,0 +1,26 @@
import axios from 'axios';
export async function updatePipelineSchedule(endpoint) {
const { url } = endpoint;
return axios({
method: 'PUT',
baseURL: url,
url: '/gitlab-org/gitlab-qa/-/pipeline_schedules/25',
headers: {
Accept: '*/*',
'Content-Type': 'application/json; charset=utf-8',
},
data: {
schedule: {
description: 'bar',
cron: '0 1 * * *',
cron_timezone: 'UTC',
active: true,
},
},
validateStatus: (status) => {
return status === 302;
},
});
}

View file

@ -0,0 +1,45 @@
/* eslint-disable @gitlab/require-i18n-strings */
import { pactWith } from 'jest-pact';
import { UpdatePipelineSchedule } from '../../../fixtures/project/pipeline_schedule/update_pipeline_schedule.fixture';
import { updatePipelineSchedule } from '../../../resources/api/pipeline_schedules';
const CONSUMER_NAME = 'PipelineSchedules#edit';
const CONSUMER_LOG = '../logs/consumer.log';
const CONTRACT_DIR = '../contracts/project/pipeline_schedule/edit';
const PROVIDER_NAME = 'PUT Edit a pipeline schedule';
// API endpoint: /pipelines.json
pactWith(
{
consumer: CONSUMER_NAME,
provider: PROVIDER_NAME,
log: CONSUMER_LOG,
dir: CONTRACT_DIR,
},
(provider) => {
describe(PROVIDER_NAME, () => {
beforeEach(() => {
const interaction = {
...UpdatePipelineSchedule.scenario,
...UpdatePipelineSchedule.request,
willRespondWith: UpdatePipelineSchedule.success,
};
provider.addInteraction(interaction);
});
it('returns a successful body', async () => {
const pipelineSchedule = await updatePipelineSchedule({
url: provider.mockService.baseUrl,
});
expect(pipelineSchedule.status).toEqual(UpdatePipelineSchedule.success.status);
});
});
},
);
/* eslint-enable @gitlab/require-i18n-strings */

View file

@ -0,0 +1,48 @@
{
"consumer": {
"name": "PipelineSchedules#edit"
},
"provider": {
"name": "PUT Edit a pipeline schedule"
},
"interactions": [
{
"description": "a request to edit a pipeline schedule",
"providerState": "a project with a pipeline schedule exists",
"request": {
"method": "PUT",
"path": "/gitlab-org/gitlab-qa/-/pipeline_schedules/25",
"headers": {
"Accept": "*/*",
"Content-Type": "application/json; charset=utf-8"
},
"body": {
"schedule": {
"description": "bar",
"cron": "0 1 * * *",
"cron_timezone": "UTC",
"active": true
}
}
},
"response": {
"status": 302,
"headers": {
"Content-Type": "text/html; charset=utf-8"
},
"body": "<html><body>You are being <a href=\"http://example.org/gitlab-org/gitlab-qa/-/pipelines/5\">redirected</a>.</body></html>",
"matchingRules": {
"$.body": {
"match": "regex",
"regex": "You are being <a href=\\\"(.)+\\\">redirected<\\/a>."
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "2.0.0"
}
}
}

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
require_relative '../../../spec_helper'
require_relative '../../../states/project/pipeline_schedule/edit_state'
module Provider
module CreateNewPipelineHelper
Pact.service_provider "PUT Edit a pipeline schedule" do
app { Environments::Test.app }
honours_pact_with 'PipelineSchedule#edit' do
pact_uri '../contracts/project/pipeline_schedule/edit/pipelineschedules#edit-put_edit_a_pipeline_schedule.json'
end
end
end
end

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
Pact.provider_states_for "PipelineSchedules#edit" do
provider_state "a project with a pipeline schedule exists" do
set_up do
user = User.find_by(name: Provider::UsersHelper::CONTRACT_USER_NAME)
namespace = create(:namespace, name: 'gitlab-org')
project = create(:project, :repository, name: 'gitlab-qa', namespace: namespace, creator: user)
project.add_maintainer(user)
create(:ci_pipeline_schedule, id: 25, project: project, owner: user)
end
end
end

View file

@ -28,10 +28,11 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
end
before do
allow(Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
allow(instance).to receive(:check_runner_upgrade_suggestion)
.and_return([nil, :not_available])
end
end
describe 'as admin', GraphQL::Query do
before do

View file

@ -73,7 +73,7 @@ RSpec.describe Backup::GitalyBackup do
let(:max_parallelism) { 3 }
it 'passes parallel option through' do
expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-parallel', '3', '-layout', 'pointer', '-id', backup_id).and_call_original
expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-parallel', '3', '-id', backup_id).and_call_original
subject.start(:create, destination, backup_id: backup_id)
subject.finish!
@ -84,7 +84,7 @@ RSpec.describe Backup::GitalyBackup do
let(:storage_parallelism) { 3 }
it 'passes parallel option through' do
expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-parallel-storage', '3', '-layout', 'pointer', '-id', backup_id).and_call_original
expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything, '-layout', 'pointer', '-parallel-storage', '3', '-id', backup_id).and_call_original
subject.start(:create, destination, backup_id: backup_id)
subject.finish!
@ -103,36 +103,6 @@ RSpec.describe Backup::GitalyBackup do
expect { subject.start(:create, destination, backup_id: backup_id) }.to raise_error(::Backup::Error, 'gitaly-backup binary not found and gitaly_backup_path is not configured')
end
context 'feature flag incremental_repository_backup disabled' do
before do
stub_feature_flags(incremental_repository_backup: false)
end
it 'creates repository bundles', :aggregate_failures do
# Add data to the wiki, design repositories, and snippets, so they will be included in the dump.
create(:wiki_page, container: project)
create(:design, :with_file, issue: create(:issue, project: project))
project_snippet = create(:project_snippet, :repository, project: project)
personal_snippet = create(:personal_snippet, :repository, author: project.first_owner)
expect(Open3).to receive(:popen2).with(expected_env, anything, 'create', '-path', anything).and_call_original
subject.start(:create, destination, backup_id: backup_id)
subject.enqueue(project, Gitlab::GlRepository::PROJECT)
subject.enqueue(project, Gitlab::GlRepository::WIKI)
subject.enqueue(project, Gitlab::GlRepository::DESIGN)
subject.enqueue(personal_snippet, Gitlab::GlRepository::SNIPPET)
subject.enqueue(project_snippet, Gitlab::GlRepository::SNIPPET)
subject.finish!
expect(File).to exist(File.join(destination, project.disk_path + '.bundle'))
expect(File).to exist(File.join(destination, project.disk_path + '.wiki.bundle'))
expect(File).to exist(File.join(destination, project.disk_path + '.design.bundle'))
expect(File).to exist(File.join(destination, personal_snippet.disk_path + '.bundle'))
expect(File).to exist(File.join(destination, project_snippet.disk_path + '.bundle'))
end
end
end
context 'hashed storage' do
@ -208,7 +178,7 @@ RSpec.describe Backup::GitalyBackup do
let(:max_parallelism) { 3 }
it 'passes parallel option through' do
expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-parallel', '3', '-layout', 'pointer').and_call_original
expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-layout', 'pointer', '-parallel', '3').and_call_original
subject.start(:restore, destination, backup_id: backup_id)
subject.finish!
@ -219,45 +189,13 @@ RSpec.describe Backup::GitalyBackup do
let(:storage_parallelism) { 3 }
it 'passes parallel option through' do
expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-parallel-storage', '3', '-layout', 'pointer').and_call_original
expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything, '-layout', 'pointer', '-parallel-storage', '3').and_call_original
subject.start(:restore, destination, backup_id: backup_id)
subject.finish!
end
end
context 'feature flag incremental_repository_backup disabled' do
before do
stub_feature_flags(incremental_repository_backup: false)
end
it 'restores from repository bundles', :aggregate_failures do
copy_bundle_to_backup_path('project_repo.bundle', project.disk_path + '.bundle')
copy_bundle_to_backup_path('wiki_repo.bundle', project.disk_path + '.wiki.bundle')
copy_bundle_to_backup_path('design_repo.bundle', project.disk_path + '.design.bundle')
copy_bundle_to_backup_path('personal_snippet_repo.bundle', personal_snippet.disk_path + '.bundle')
copy_bundle_to_backup_path('project_snippet_repo.bundle', project_snippet.disk_path + '.bundle')
expect(Open3).to receive(:popen2).with(expected_env, anything, 'restore', '-path', anything).and_call_original
subject.start(:restore, destination, backup_id: backup_id)
subject.enqueue(project, Gitlab::GlRepository::PROJECT)
subject.enqueue(project, Gitlab::GlRepository::WIKI)
subject.enqueue(project, Gitlab::GlRepository::DESIGN)
subject.enqueue(personal_snippet, Gitlab::GlRepository::SNIPPET)
subject.enqueue(project_snippet, Gitlab::GlRepository::SNIPPET)
subject.finish!
collect_commit_shas = -> (repo) { repo.commits('master', limit: 10).map(&:sha) }
expect(collect_commit_shas.call(project.repository)).to match_array(['393a7d860a5a4c3cc736d7eb00604e3472bb95ec'])
expect(collect_commit_shas.call(project.wiki.repository)).to match_array(['c74b9948d0088d703ee1fafeddd9ed9add2901ea'])
expect(collect_commit_shas.call(project.design_repository)).to match_array(['c3cd4d7bd73a51a0f22045c3a4c871c435dc959d'])
expect(collect_commit_shas.call(personal_snippet.repository)).to match_array(['3b3c067a3bc1d1b695b51e2be30c0f8cf698a06e'])
expect(collect_commit_shas.call(project_snippet.repository)).to match_array(['6e44ba56a4748be361a841e759c20e421a1651a1'])
end
end
it 'raises when the exit code not zero' do
expect(subject).to receive(:bin_path).and_return(Gitlab::Utils.which('false'))

View file

@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::RunnerReleases do
subject { described_class.instance }
let(:runner_releases_url) { 'the release API URL' }
let(:runner_releases_url) { 'http://testurl.com/runner_public_releases' }
def releases
subject.releases
@ -18,7 +18,7 @@ RSpec.describe Gitlab::Ci::RunnerReleases do
before do
subject.reset_backoff!
stub_application_setting(public_runner_releases_url: runner_releases_url)
allow(subject).to receive(:runner_releases_url).and_return(runner_releases_url)
end
describe 'caching behavior', :use_clean_rails_memory_store_caching do

View file

@ -5,24 +5,20 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
using RSpec::Parameterized::TableSyntax
subject(:instance) { described_class.new(gitlab_version, runner_releases) }
describe '#check_runner_upgrade_suggestion' do
subject(:result) { described_class.instance.check_runner_upgrade_suggestion(runner_version) }
subject(:result) { instance.check_runner_upgrade_suggestion(runner_version) }
let(:gitlab_version) { '14.1.1' }
let(:parsed_runner_version) { ::Gitlab::VersionInfo.parse(runner_version, parse_suffix: true) }
before do
allow(described_class.instance).to receive(:gitlab_version)
.and_return(::Gitlab::VersionInfo.parse(gitlab_version))
end
let(:runner_releases) { instance_double(Gitlab::Ci::RunnerReleases) }
context 'with failing Gitlab::Ci::RunnerReleases request' do
let(:runner_version) { '14.1.123' }
let(:runner_releases_double) { instance_double(Gitlab::Ci::RunnerReleases) }
before do
allow(Gitlab::Ci::RunnerReleases).to receive(:instance).and_return(runner_releases_double)
allow(runner_releases_double).to receive(:releases).and_return(nil)
allow(runner_releases).to receive(:releases).and_return(nil)
end
it 'returns :error' do
@ -31,10 +27,13 @@ RSpec.describe Gitlab::Ci::RunnerUpgradeCheck do
end
context 'with available_runner_releases configured' do
before do
url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url
let(:runner_releases) { Gitlab::Ci::RunnerReleases.instance }
let(:runner_releases_url) do
::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url
end
WebMock.stub_request(:get, url).to_return(
before do
WebMock.stub_request(:get, runner_releases_url).to_return(
body: available_runner_releases.map { |v| { name: v } }.to_json,
status: 200,
headers: { 'Content-Type' => 'application/json' }

View file

@ -37,7 +37,9 @@ RSpec.describe 'Query.runners' do
end
before do
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_suggestion)
allow_next_instance_of(::Gitlab::Ci::RunnerUpgradeCheck) do |instance|
allow(instance).to receive(:check_runner_upgrade_suggestion)
end
post_graphql(query, current_user: current_user)
end

View file

@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute' do
include RunnerReleasesHelper
subject(:execute) { described_class.new.execute }
let_it_be(:runner_14_0_1) { create(:ci_runner, version: '14.0.1') }
@ -11,12 +13,12 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
end
context 'with RunnerUpgradeCheck recommending 14.0.2' do
let(:upgrade_check) { instance_double(::Gitlab::Ci::RunnerUpgradeCheck) }
before do
stub_const('Ci::Runners::ReconcileExistingRunnerVersionsService::VERSION_BATCH_SIZE', 1)
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :recommended])
allow(::Gitlab::Ci::RunnerUpgradeCheck).to receive(:new).and_return(upgrade_check).once
end
context 'with runner with new version' do
@ -25,8 +27,9 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
let!(:runner_14_0_0) { create(:ci_runner, version: '14.0.0') }
before do
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
allow(upgrade_check).to receive(:check_runner_upgrade_suggestion)
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :recommended])
allow(upgrade_check).to receive(:check_runner_upgrade_suggestion)
.with('14.0.2')
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :not_available])
.once
@ -58,8 +61,7 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
let!(:runner_version_14_0_2) { create(:ci_runner_version, version: '14.0.2', status: :not_available) }
before do
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
allow(upgrade_check).to receive(:check_runner_upgrade_suggestion)
.and_return([::Gitlab::VersionInfo.new(14, 0, 2), :not_available])
end
@ -80,8 +82,7 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
context 'with no runner version changes' do
before do
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
allow(upgrade_check).to receive(:check_runner_upgrade_suggestion)
.and_return([::Gitlab::VersionInfo.new(14, 0, 1), :not_available])
end
@ -100,8 +101,7 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
context 'with failing version check' do
before do
allow(::Gitlab::Ci::RunnerUpgradeCheck.instance)
.to receive(:check_runner_upgrade_suggestion)
allow(upgrade_check).to receive(:check_runner_upgrade_suggestion)
.and_return([::Gitlab::VersionInfo.new(14, 0, 1), :error])
end
@ -120,18 +120,8 @@ RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute'
end
context 'integration testing with Gitlab::Ci::RunnerUpgradeCheck' do
let(:available_runner_releases) do
%w[14.0.0 14.0.1]
end
before do
url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url
WebMock.stub_request(:get, url).to_return(
body: available_runner_releases.map { |v| { name: v } }.to_json,
status: 200,
headers: { 'Content-Type' => 'application/json' }
)
stub_runner_releases(%w[14.0.0 14.0.1])
end
it 'does not modify ci_runner_versions entries', :aggregate_failures do

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module RunnerReleasesHelper
def stub_runner_releases(available_runner_releases, gitlab_version: nil)
# We stub the behavior of RunnerReleases so that we don't need to rely on flaky global settings
available_runner_releases = available_runner_releases
.map { |v| ::Gitlab::VersionInfo.parse(v, parse_suffix: true) }
.sort
releases_by_minor = available_runner_releases
.group_by(&:without_patch)
.transform_values(&:max)
runner_releases_double = instance_double(Gitlab::Ci::RunnerReleases)
allow(::Gitlab::Ci::RunnerUpgradeCheck).to receive(:new).and_wrap_original do |method, *_original_args|
gitlab_version ||= available_runner_releases.max
method.call(gitlab_version, runner_releases_double)
end
allow(runner_releases_double).to receive(:releases).and_return(available_runner_releases)
allow(runner_releases_double).to receive(:releases_by_minor).and_return(releases_by_minor)
end
end

View file

@ -11,3 +11,9 @@ RSpec.shared_examples 'it does not render help text' do
expect(page).not_to have_css('[data-testid="pajamas-component-help-text"]')
end
end
RSpec.shared_examples 'it renders unchecked checkbox with value of `1`' do
it 'renders unchecked checkbox with value of `1`' do
expect(page).to have_unchecked_field(label, with: '1')
end
end