Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b54ba745ea
commit
1acb6e46fe
47 changed files with 778 additions and 415 deletions
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
212
app/assets/stylesheets/page_bundles/profile.scss
Normal file
212
app/assets/stylesheets/page_bundles/profile.scss
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
6
app/components/pajamas/checkbox_tag_component.html.haml
Normal file
6
app/components/pajamas/checkbox_tag_component.html.haml
Normal 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
|
44
app/components/pajamas/checkbox_tag_component.rb
Normal file
44
app/components/pajamas/checkbox_tag_component.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 project’s 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' }
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
11
doc/development/single_table_inheritance.md
Normal file
11
doc/development/single_table_inheritance.md
Normal 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 -->
|
|
@ -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
|
||||
|
|
|
@ -32,15 +32,12 @@ 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
|
||||
if type == :create
|
||||
args += ['-incremental'] if incremental?
|
||||
args += ['-id', backup_id] if backup_id
|
||||
end
|
||||
|
||||
@input_stream, stdout, @thread = Open3.popen2(build_env, bin_path, command, '-path', backup_repos_path, *args)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
34
lib/tasks/contracts/pipeline_schedules.rake
Normal file
34
lib/tasks/contracts/pipeline_schedules.rake
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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|
|
||||
|
|
59
spec/components/pajamas/checkbox_tag_component_spec.rb
Normal file
59
spec/components/pajamas/checkbox_tag_component_spec.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 =
|
||||
|
|
26
spec/contracts/consumer/resources/api/pipeline_schedules.js
Normal file
26
spec/contracts/consumer/resources/api/pipeline_schedules.js
Normal 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;
|
||||
},
|
||||
});
|
||||
}
|
|
@ -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 */
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -28,9 +28,10 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
|
|||
end
|
||||
|
||||
before do
|
||||
allow(Gitlab::Ci::RunnerUpgradeCheck.instance)
|
||||
.to receive(:check_runner_upgrade_suggestion)
|
||||
.and_return([nil, :not_available])
|
||||
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
|
||||
|
|
|
@ -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'))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
22
spec/support/helpers/runner_releases_helper.rb
Normal file
22
spec/support/helpers/runner_releases_helper.rb
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue