summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-22 21:15:07 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-22 21:15:07 +0000
commite53eae82b097308623e77a69f8cc3138cca3cf68 (patch)
treed8a99e1a3ca49739a8e7f2cad4b2f4c622c6c8c4
parentde0e57e387034634a861555b878923cd077a039f (diff)
downloadgitlab-ce-e53eae82b097308623e77a69f8cc3138cca3cf68.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml6
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/environments/components/new_environment_item.vue2
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue6
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss4
-rw-r--r--app/graphql/graphql_triggers.rb2
-rw-r--r--app/views/users/show.html.haml301
-rw-r--r--doc/administration/clusters/kas.md27
-rw-r--r--doc/development/documentation/styleguide/word_list.md2
-rw-r--r--doc/update/plan_your_upgrade.md2
-rw-r--r--qa/qa/page/project/job/show.rb4
-rw-r--r--scripts/gitlab_component_helpers.sh73
-rw-r--r--spec/features/users/show_spec.rb8
-rw-r--r--spec/frontend/environments/new_environment_item_spec.js1
-rw-r--r--spec/graphql/graphql_triggers_spec.rb14
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb32
16 files changed, 279 insertions, 207 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 0039e117d57..88dbd1649b0 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -104,9 +104,9 @@ retrieve-frontend-fixtures:
- .frontend:rules:default-frontend-jobs
stage: prepare
script:
- - export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}"
- source scripts/utils.sh
- source scripts/gitlab_component_helpers.sh
+ - export_fixtures_sha_for_download
- |
if check_fixtures_download; then
run_timed_command "download_and_extract_fixtures"
@@ -129,9 +129,9 @@ retrieve-frontend-fixtures:
CRYSTALBALL: "false"
WEBPACK_VENDOR_DLL: "true"
script:
- - export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}"
- source scripts/utils.sh
- source scripts/gitlab_component_helpers.sh
+ - export_fixtures_sha_for_download
- |
if check_fixtures_download; then
exit 0
@@ -186,9 +186,9 @@ upload-frontend-fixtures:
stage: fixtures
needs: ["rspec-all frontend_fixture"]
script:
- - export FIXTURES_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}"
- source scripts/utils.sh
- source scripts/gitlab_component_helpers.sh
+ - export_fixtures_sha_for_upload
- 'fixtures_archive_doesnt_exist || { echoinfo "INFO: Exiting early as package exists."; exit 0; }'
- run_timed_command "create_fixtures_package"
- run_timed_command "upload_fixtures_package"
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 168cb96d4c5..53d503b7d85 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-8421e7ceb0d9cb7164eb48f02b6e91a0f6d92e05
+98d26efad3a10c52e1ad20429cffb4e6605510d5
diff --git a/app/assets/javascripts/environments/components/new_environment_item.vue b/app/assets/javascripts/environments/components/new_environment_item.vue
index 2ec6e12b8b3..a945e89393b 100644
--- a/app/assets/javascripts/environments/components/new_environment_item.vue
+++ b/app/assets/javascripts/environments/components/new_environment_item.vue
@@ -223,7 +223,7 @@ export default {
:icon="icon"
:aria-label="label"
size="small"
- category="tertiary"
+ category="secondary"
@click="toggleCollapse"
/>
<gl-link
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
index 2018942a7e8..14aaaa219e9 100644
--- a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
+++ b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
@@ -45,7 +45,9 @@ export default {
data-testid="artifacts-remove-timeline"
>
<span v-if="isExpired">{{ s__('Job|The artifacts were removed') }}</span>
- <span v-if="willExpire">{{ s__('Job|The artifacts will be removed') }}</span>
+ <span v-if="willExpire" data-qa-selector="artifacts_unlocked_message_content">{{
+ s__('Job|The artifacts will be removed')
+ }}</span>
<timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
<gl-link
:href="helpUrl"
@@ -57,7 +59,7 @@ export default {
</gl-link>
</p>
<p v-else-if="isLocked" class="build-detail-row">
- <span data-testid="job-locked-message">{{
+ <span data-testid="job-locked-message" data-qa-selector="artifacts_locked_message_content">{{
s__(
'Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.',
)
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index 4d07e4259a0..04a7590d531 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -55,6 +55,10 @@ $item-remove-button-space: 42px;
.item-weight .board-card-info-icon {
min-width: $gl-padding;
cursor: help;
+
+ &:focus {
+ @include gl-focus;
+ }
}
.confidential-icon {
diff --git a/app/graphql/graphql_triggers.rb b/app/graphql/graphql_triggers.rb
index 89656f1e018..d18f57740c3 100644
--- a/app/graphql/graphql_triggers.rb
+++ b/app/graphql/graphql_triggers.rb
@@ -48,6 +48,8 @@ module GraphqlTriggers
end
def self.merge_request_merge_status_updated(merge_request)
+ return unless Feature.enabled?(:realtime_mr_status_change, merge_request.project)
+
GitlabSchema.subscriptions.trigger(
'mergeRequestMergeStatusUpdated', { issuable_id: merge_request.to_gid }, merge_request
)
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 08ebdb64b52..5732a2f88e9 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -1,6 +1,6 @@
- @hide_top_links = true
-- @hide_breadcrumbs = true
- @no_container = true
+- breadcrumb_title user_display_name(@user)
- page_title user_display_name(@user)
- page_description @user.bio unless @user.blocked? || !@user.confirmed?
- page_itemtype 'http://schema.org/Person'
@@ -14,161 +14,162 @@
= auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity")
.user-profile
- .cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] }
- = render layout: 'users/cover_controls' do
- - if @user == current_user
- = render Pajamas::ButtonComponent.new(href: profile_path,
- icon: 'pencil',
- button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- - elsif current_user
- #js-report-abuse{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @user.id, reported_from_url: user_url(@user) } }
- - verified_gpg_keys = @user.gpg_keys.select(&:verified?)
- - if verified_gpg_keys.any?
- = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path,
- icon: 'key',
- button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- - if can?(current_user, :read_user_profile, @user)
- = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options),
- icon: 'rss',
- button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- - if current_user && current_user.admin?
- = render Pajamas::ButtonComponent.new(href: [:admin, @user],
- icon: 'user',
- button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}})
- - if current_user && current_user.id != @user.id
- - if current_user.following?(@user)
- = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
- = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do
- = _('Unfollow')
- - else
- = form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
- = render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do
- = _('Follow')
+ %div{ class: container_class }
+ .cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty? || show_super_sidebar?)] }
+ = render layout: 'users/cover_controls' do
+ - if @user == current_user
+ = render Pajamas::ButtonComponent.new(href: profile_path,
+ icon: 'pencil',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
+ - elsif current_user
+ #js-report-abuse{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @user.id, reported_from_url: user_url(@user) } }
+ - verified_gpg_keys = @user.gpg_keys.select(&:verified?)
+ - if verified_gpg_keys.any?
+ = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path,
+ icon: 'key',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
+ - if can?(current_user, :read_user_profile, @user)
+ = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options),
+ icon: 'rss',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
+ - if current_user && current_user.admin?
+ = render Pajamas::ButtonComponent.new(href: [:admin, @user],
+ icon: 'user',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}})
+ - if current_user && current_user.id != @user.id
+ - if current_user.following?(@user)
+ = form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
+ = render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do
+ = _('Unfollow')
+ - else
+ = form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
+ = render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do
+ = _('Follow')
- .profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] }
- .gl-display-inline-block.gl-mx-8.gl-vertical-align-top
- .avatar-holder
- = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do
- = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" })
- #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } }
- .gl-display-inline-block.gl-vertical-align-top.gl-text-left
- - if @user.blocked? || !@user.confirmed?
- .user-info
- %h1.cover-title.gl-my-0
- = user_display_name(@user)
- = render "users/profile_basic_info"
- - else
- .user-info
- %h1.cover-title.gl-my-0{ itemprop: 'name' }
- = @user.name
- - if @user.pronouns.present?
- %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
- = "(#{@user.pronouns})"
- - if @user.status&.busy?
- %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)")
+ .profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] }
+ .gl-display-inline-block.gl-mx-8.gl-vertical-align-top
+ .avatar-holder
+ = link_to avatar_icon_for_user(@user, 400, current_user: current_user), target: '_blank', rel: 'noopener noreferrer' do
+ = render Pajamas::AvatarComponent.new(@user, alt: "", size: 96, avatar_options: { itemprop: "image" })
+ #js-user-achievements{ data: { root_url: root_url, user_id: @user.id } }
+ .gl-display-inline-block.gl-vertical-align-top.gl-text-left
+ - if @user.blocked? || !@user.confirmed?
+ .user-info
+ %h1.cover-title.gl-my-0
+ = user_display_name(@user)
+ = render "users/profile_basic_info"
+ - else
+ .user-info
+ %h1.cover-title.gl-my-0{ itemprop: 'name' }
+ = @user.name
+ - if @user.pronouns.present?
+ %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
+ = "(#{@user.pronouns})"
+ - if @user.status&.busy?
+ %span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle= s_("UserProfile|(Busy)")
- - if @user.pronunciation.present?
- .gl-align-items-center
- %p.gl-mb-4.gl-text-gray-500.gl-max-w-80.gl-mx-auto= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation }
+ - if @user.pronunciation.present?
+ .gl-align-items-center
+ %p.gl-mb-4.gl-text-gray-500.gl-max-w-80.gl-mx-auto= s_("UserProfile|Pronounced as: %{pronunciation}") % { pronunciation: @user.pronunciation }
- - if @user.status&.customized?
- .cover-status.gl-display-inline-flex.gl-align-items-center.gl-mb-3
- = emoji_icon(@user.status.emoji, class: 'gl-mr-2')
- = markdown_field(@user.status, :message)
- = render "users/profile_basic_info"
- - user_local_time = local_time(@user.timezone)
- - if @user.location.present? || user_local_time.present? || work_information(@user).present?
+ - if @user.status&.customized?
+ .cover-status.gl-display-inline-flex.gl-align-items-center.gl-mb-3
+ = emoji_icon(@user.status.emoji, class: 'gl-mr-2')
+ = markdown_field(@user.status, :message)
+ = render "users/profile_basic_info"
+ - user_local_time = local_time(@user.timezone)
+ - if @user.location.present? || user_local_time.present? || work_information(@user).present?
+ .gl-text-gray-900
+ - if @user.location.present?
+ = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do
+ = sprite_icon('location', css_class: 'fgray')
+ %span{ itemprop: 'addressLocality' }
+ = @user.location
+ - if user_local_time.present?
+ = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do
+ = sprite_icon('clock', css_class: 'fgray')
+ %span
+ = user_local_time
+ - if work_information(@user).present?
+ = render 'middle_dot_divider', stacking: true do
+ = sprite_icon('work', css_class: 'fgray')
+ %span
+ = work_information(@user, with_schema_markup: true)
.gl-text-gray-900
- - if @user.location.present?
- = render 'middle_dot_divider', stacking: true, itemprop: 'address', itemscope: true, itemtype: 'https://schema.org/PostalAddress' do
- = sprite_icon('location', css_class: 'fgray')
- %span{ itemprop: 'addressLocality' }
- = @user.location
- - if user_local_time.present?
- = render 'middle_dot_divider', stacking: true, data: { testid: 'user-local-time' } do
- = sprite_icon('clock', css_class: 'fgray')
- %span
- = user_local_time
- - if work_information(@user).present?
+ - if @user.skype.present?
+ = render 'middle_dot_divider' do
+ = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do
+ = sprite_icon('skype', css_class: 'skype-icon')
+ - if @user.linkedin.present?
+ = render 'middle_dot_divider' do
+ = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('linkedin', css_class: 'linkedin-icon')
+ - if @user.twitter.present?
+ = render 'middle_dot_divider', breakpoint: 'sm' do
+ = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('twitter', css_class: 'twitter-icon')
+ - if @user.discord.present?
+ = render 'middle_dot_divider', breakpoint: 'sm' do
+ = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do
+ = sprite_icon('discord', css_class: 'discord-icon')
+ - if @user.website_url.present?
+ = render 'middle_dot_divider', stacking: true do
+ - if Feature.enabled?(:security_auto_fix) && @user.bot?
+ = sprite_icon('question', css_class: 'gl-text-blue-600')
+ = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url'
+ - if display_public_email?(@user)
= render 'middle_dot_divider', stacking: true do
- = sprite_icon('work', css_class: 'fgray')
- %span
- = work_information(@user, with_schema_markup: true)
- .gl-text-gray-900
- - if @user.skype.present?
- = render 'middle_dot_divider' do
- = link_to "skype:#{@user.skype}", class: 'gl-hover-text-decoration-none', title: "Skype" do
- = sprite_icon('skype', css_class: 'skype-icon')
- - if @user.linkedin.present?
- = render 'middle_dot_divider' do
- = link_to linkedin_url(@user), class: 'gl-hover-text-decoration-none', title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('linkedin', css_class: 'linkedin-icon')
- - if @user.twitter.present?
- = render 'middle_dot_divider', breakpoint: 'sm' do
- = link_to twitter_url(@user), class: 'gl-hover-text-decoration-none', title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('twitter', css_class: 'twitter-icon')
- - if @user.discord.present?
- = render 'middle_dot_divider', breakpoint: 'sm' do
- = link_to discord_url(@user), class: 'gl-hover-text-decoration-none', title: "Discord", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = sprite_icon('discord', css_class: 'discord-icon')
- - if @user.website_url.present?
- = render 'middle_dot_divider', stacking: true do
- - if Feature.enabled?(:security_auto_fix) && @user.bot?
- = sprite_icon('question', css_class: 'gl-text-blue-600')
- = link_to @user.short_website_url, @user.full_website_url, target: '_blank', rel: 'me noopener noreferrer nofollow', itemprop: 'url'
- - if display_public_email?(@user)
- = render 'middle_dot_divider', stacking: true do
- = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email'
- - if @user.bio.present? && @user.confirmed? && !@user.blocked?
- %p.profile-user-bio.gl-mb-3
- = @user.bio
+ = link_to @user.public_email, "mailto:#{@user.public_email}", itemprop: 'email'
+ - if @user.bio.present? && @user.confirmed? && !@user.blocked?
+ %p.profile-user-bio.gl-mb-3
+ = @user.bio
- - if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
- .scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
- - if profile_tab?(:overview)
- %li.js-overview-tab
- = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do
- = s_('UserProfile|Overview')
- - if profile_tab?(:activity)
- %li.js-activity-tab
- = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
- = s_('UserProfile|Activity')
- - unless Feature.enabled?(:security_auto_fix) && @user.bot?
- - if profile_tab?(:groups)
- %li.js-groups-tab
- = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
- = s_('UserProfile|Groups')
- - if profile_tab?(:contributed)
- %li.js-contributed-tab
- = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
- = s_('UserProfile|Contributed projects')
- - if profile_tab?(:projects)
- %li.js-projects-tab
- = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
- = s_('UserProfile|Personal projects')
- - if profile_tab?(:starred)
- %li.js-starred-tab
- = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
- = s_('UserProfile|Starred projects')
- - if profile_tab?(:snippets)
- %li.js-snippets-tab
- = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
- = s_('UserProfile|Snippets')
- - if profile_tab?(:followers)
- %li.js-followers-tab
- = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do
- = s_('UserProfile|Followers')
- = gl_badge_tag @user.followers.count, size: :sm
- - if profile_tab?(:following)
- %li.js-following-tab
- = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json), qa_selector: 'following_tab' } do
- = s_('UserProfile|Following')
- = gl_badge_tag @user.followees.count, size: :sm
- - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user)
- #js-profile-tabs{ data: user_profile_tabs_app_data(@user) }
+ - if !profile_tabs.empty? && !Feature.enabled?(:profile_tabs_vue, current_user)
+ .scrolling-tabs-container{ class: [('gl-display-none' if show_super_sidebar?)] }
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ %ul.nav-links.user-profile-nav.scrolling-tabs.nav.nav-tabs
+ - if profile_tab?(:overview)
+ %li.js-overview-tab
+ = link_to user_path, data: { target: 'div#js-overview', action: 'overview', toggle: 'tab' } do
+ = s_('UserProfile|Overview')
+ - if profile_tab?(:activity)
+ %li.js-activity-tab
+ = link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
+ = s_('UserProfile|Activity')
+ - unless Feature.enabled?(:security_auto_fix) && @user.bot?
+ - if profile_tab?(:groups)
+ %li.js-groups-tab
+ = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
+ = s_('UserProfile|Groups')
+ - if profile_tab?(:contributed)
+ %li.js-contributed-tab
+ = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
+ = s_('UserProfile|Contributed projects')
+ - if profile_tab?(:projects)
+ %li.js-projects-tab
+ = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
+ = s_('UserProfile|Personal projects')
+ - if profile_tab?(:starred)
+ %li.js-starred-tab
+ = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
+ = s_('UserProfile|Starred projects')
+ - if profile_tab?(:snippets)
+ %li.js-snippets-tab
+ = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
+ = s_('UserProfile|Snippets')
+ - if profile_tab?(:followers)
+ %li.js-followers-tab
+ = link_to user_followers_path, data: { target: 'div#followers', action: 'followers', toggle: 'tab', endpoint: user_followers_path(format: :json) } do
+ = s_('UserProfile|Followers')
+ = gl_badge_tag @user.followers.count, size: :sm
+ - if profile_tab?(:following)
+ %li.js-following-tab
+ = link_to user_following_path, data: { target: 'div#following', action: 'following', toggle: 'tab', endpoint: user_following_path(format: :json), qa_selector: 'following_tab' } do
+ = s_('UserProfile|Following')
+ = gl_badge_tag @user.followees.count, size: :sm
+ - if !profile_tabs.empty? && Feature.enabled?(:profile_tabs_vue, current_user)
+ #js-profile-tabs{ data: user_profile_tabs_app_data(@user) }
%div{ class: container_class }
- unless Feature.enabled?(:profile_tabs_vue, current_user)
.tab-content
diff --git a/doc/administration/clusters/kas.md b/doc/administration/clusters/kas.md
index 9d2629e314a..6d6e8e5513c 100644
--- a/doc/administration/clusters/kas.md
+++ b/doc/administration/clusters/kas.md
@@ -43,6 +43,33 @@ To enable the agent server on a single node:
For additional configuration options, see the **Enable GitLab KAS** section of the
[`gitlab.rb.template`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/master/files/gitlab-config-template/gitlab.rb.template).
+##### Configure KAS to listen on a UNIX socket
+
+If you use GitLab behind a proxy, KAS might not work correctly. You can resolve this issue on a single-node installation, you can configure KAS to listen on a UNIX socket.
+
+To configure KAS to listen on a UNIX socket:
+
+1. Create a directory for the KAS sockets:
+
+ ```shell
+ sudo mkdir -p /var/opt/gitlab/gitlab-kas/sockets/
+ ```
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_kas['internal_api_listen_network'] = 'unix'
+ gitlab_kas['internal_api_listen_address'] = '/var/opt/gitlab/gitlab-kas/sockets/internal-api.socket'
+ gitlab_kas['private_api_listen_network'] = 'unix'
+ gitlab_kas['private_api_listen_address'] = '/var/opt/gitlab/gitlab-kas/sockets/private-api.socket'
+ gitlab_kas['env'] = {
+ 'SSL_CERT_DIR' => "/opt/gitlab/embedded/ssl/certs/",
+ 'OWN_PRIVATE_API_URL' => 'unix:///var/opt/gitlab/gitlab-kas/sockets/private-api.socket'
+ }
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
#### Enable on multiple nodes
To enable the agent server on multiple nodes:
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 2dd3bede19a..9ecddd08103 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -320,7 +320,7 @@ Use **compute credits** instead of these (or similar) terms:
- **CI pipeline minutes**
- **pipeline minutes quota**
-As of March, 2022, this language is still being standardized in the documentation and UI.
+This language is still being standardized in the documentation and UI beginning in March, 2023.
For more information, see [issue 5218](https://gitlab.com/gitlab-com/Product/-/issues/5218).
## confirmation dialog
diff --git a/doc/update/plan_your_upgrade.md b/doc/update/plan_your_upgrade.md
index 0d0084cf530..fd5e1ac8c30 100644
--- a/doc/update/plan_your_upgrade.md
+++ b/doc/update/plan_your_upgrade.md
@@ -173,7 +173,7 @@ If you have Kubernetes clusters connected with GitLab, [upgrade your GitLab agen
#### Elasticsearch
Before updating GitLab, confirm advanced search migrations are complete by
-[checking for pending advanced search migrations](background_migrations.md).
+[checking for pending advanced search migrations](index.md#checking-for-pending-advanced-search-migrations).
After updating GitLab, you may have to upgrade
[Elasticsearch if the new version breaks compatibility](../integration/advanced_search/elasticsearch.md#version-requirements).
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 444c67cfe4f..41a2986e300 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -69,11 +69,11 @@ module QA
end
def has_locked_artifact?
- has_text?('will not be deleted')
+ has_element? :artifacts_locked_message_content
end
def has_unlocked_artifact?
- has_text?('will be removed')
+ has_element? :artifacts_unlocked_message_content
end
private
diff --git a/scripts/gitlab_component_helpers.sh b/scripts/gitlab_component_helpers.sh
index 798135a5490..cf9b042b529 100644
--- a/scripts/gitlab_component_helpers.sh
+++ b/scripts/gitlab_component_helpers.sh
@@ -53,8 +53,6 @@ export GITLAB_ASSETS_PACKAGE_URL="${API_PACKAGES_BASE_URL}/assets/${NODE_ENV}-${
# Fixtures constants
export FIXTURES_PATH="tmp/tests/frontend/**/*"
-export FIXTURES_PACKAGE="fixtures-${FIXTURES_SHA:-}.tar.gz"
-export FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${FIXTURES_SHA:-}/${FIXTURES_PACKAGE}"
# Generic helper functions
function archive_doesnt_exist() {
@@ -62,12 +60,12 @@ function archive_doesnt_exist() {
status=$(curl -I --silent --retry 3 --output /dev/null -w "%{http_code}" "${package_url}")
- if [[ "${status}" != "200" ]]; then
- echoinfo "The archive was not found. The server returned status ${status}."
- return 0
- else
+ if [[ "${status}" = "200" ]]; then
echoinfo "The archive was found. The server returned status ${status}."
return 1
+ else
+ echoinfo "The archive was not found. The server returned status ${status}."
+ return 0
fi
}
@@ -160,28 +158,6 @@ function upload_gitlab_assets_package() {
}
# Fixtures functions
-function download_and_extract_fixtures() {
- read_curl_package "${FIXTURES_PACKAGE_URL}" | extract_package
-}
-
-function fixtures_archive_doesnt_exist() {
- echoinfo "Checking if the package is available at ${FIXTURES_PACKAGE_URL} ..."
-
- archive_doesnt_exist "${FIXTURES_PACKAGE_URL}"
-}
-
-function fixtures_directory_exists() {
- local fixtures_directory="tmp/tests/frontend/"
-
- if [[ -d "${fixtures_directory}" ]]; then
- echo "${fixtures_directory} directory exists"
- return 0
- else
- echo "${fixtures_directory} directory does not exist"
- return 1
- fi
-}
-
function check_fixtures_download() {
if [[ "${REUSE_FRONTEND_FIXTURES_ENABLED:-}" != "true" ]]; then
return 1
@@ -208,8 +184,41 @@ function create_fixtures_package() {
create_package "${FIXTURES_PACKAGE}" "${FIXTURES_PATH}"
}
-function upload_fixtures_package() {
- upload_package "${FIXTURES_PACKAGE}" "${FIXTURES_PACKAGE_URL}"
+function download_and_extract_fixtures() {
+ read_curl_package "${FIXTURES_PACKAGE_URL}" | extract_package
+}
+
+function export_fixtures_package_variables() {
+ export FIXTURES_PACKAGE="fixtures-${FIXTURES_SHA}.tar.gz"
+ export FIXTURES_PACKAGE_URL="${API_PACKAGES_BASE_URL}/fixtures/${FIXTURES_SHA}/${FIXTURES_PACKAGE}"
+}
+
+function export_fixtures_sha_for_download() {
+ export FIXTURES_SHA="${CI_MERGE_REQUEST_TARGET_BRANCH_SHA:-${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_SHA}}"
+ export_fixtures_package_variables
+}
+
+function export_fixtures_sha_for_upload() {
+ export FIXTURES_SHA="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}"
+ export_fixtures_package_variables
+}
+
+function fixtures_archive_doesnt_exist() {
+ echoinfo "Checking if the package is available at ${FIXTURES_PACKAGE_URL} ..."
+
+ archive_doesnt_exist "${FIXTURES_PACKAGE_URL}"
+}
+
+function fixtures_directory_exists() {
+ local fixtures_directory="tmp/tests/frontend/"
+
+ if [[ -d "${fixtures_directory}" ]]; then
+ echo "${fixtures_directory} directory exists"
+ return 0
+ else
+ echo "${fixtures_directory} directory does not exist"
+ return 1
+ fi
}
function only_js_files_changed {
@@ -235,3 +244,7 @@ function only_js_files_changed {
echoinfo "Only JS files were changed"
return 0
}
+
+function upload_fixtures_package() {
+ upload_package "${FIXTURES_PACKAGE}" "${FIXTURES_PACKAGE_URL}"
+}
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index 9aef3ed7cd6..fab87f6dc71 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -15,6 +15,14 @@ RSpec.describe 'User page', feature_category: :user_profile do
expect(page).to have_content("User ID: #{user.id}")
end
+ it 'shows name on breadcrumbs' do
+ subject
+
+ page.within '.breadcrumbs' do
+ expect(page).to have_content(user.name)
+ end
+ end
+
context 'with public profile' do
context 'with `profile_tabs_vue` feature flag disabled' do
before do
diff --git a/spec/frontend/environments/new_environment_item_spec.js b/spec/frontend/environments/new_environment_item_spec.js
index c04ff896794..b2088ad410b 100644
--- a/spec/frontend/environments/new_environment_item_spec.js
+++ b/spec/frontend/environments/new_environment_item_spec.js
@@ -382,6 +382,7 @@ describe('~/environments/components/new_environment_item.vue', () => {
const button = await expandCollapsedSection();
expect(button.attributes('aria-label')).toBe(__('Collapse'));
+ expect(button.props('category')).toBe('secondary');
expect(collapse.attributes('visible')).toBe('visible');
expect(icon.props('name')).toBe('chevron-lg-down');
expect(environmentName.classes('gl-font-weight-bold')).toBe(true);
diff --git a/spec/graphql/graphql_triggers_spec.rb b/spec/graphql/graphql_triggers_spec.rb
index 00b5aec366e..08b8f67c4bc 100644
--- a/spec/graphql/graphql_triggers_spec.rb
+++ b/spec/graphql/graphql_triggers_spec.rb
@@ -115,6 +115,20 @@ RSpec.describe GraphqlTriggers do
GraphqlTriggers.merge_request_merge_status_updated(merge_request)
end
+
+ context 'when realtime_mr_status_change feature flag is disabled' do
+ before do
+ stub_feature_flags(realtime_mr_status_change: false)
+ end
+
+ it 'does not trigger mergeRequestMergeStatusUpdated subscription' do
+ merge_request = build_stubbed(:merge_request)
+
+ expect(GitlabSchema.subscriptions).not_to receive(:trigger)
+
+ GraphqlTriggers.merge_request_merge_status_updated(merge_request)
+ end
+ end
end
describe '.merge_request_approval_state_updated' do
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index 3f72896939d..de259342998 100644
--- a/spec/lib/banzai/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -2,25 +2,25 @@
require 'spec_helper'
-RSpec.shared_examples 'an external link with rel attribute', feature_category: :team_planning do
- it 'adds rel="nofollow" to external links' do
- expect(doc.at_css('a')).to have_attribute('rel')
- expect(doc.at_css('a')['rel']).to include 'nofollow'
- end
+RSpec.describe Banzai::Filter::ExternalLinkFilter, feature_category: :team_planning do
+ include FilterSpecHelper
- it 'adds rel="noreferrer" to external links' do
- expect(doc.at_css('a')).to have_attribute('rel')
- expect(doc.at_css('a')['rel']).to include 'noreferrer'
- end
+ shared_examples 'an external link with rel attribute' do
+ it 'adds rel="nofollow" to external links' do
+ expect(doc.at_css('a')).to have_attribute('rel')
+ expect(doc.at_css('a')['rel']).to include 'nofollow'
+ end
- it 'adds rel="noopener" to external links' do
- expect(doc.at_css('a')).to have_attribute('rel')
- expect(doc.at_css('a')['rel']).to include 'noopener'
- end
-end
+ it 'adds rel="noreferrer" to external links' do
+ expect(doc.at_css('a')).to have_attribute('rel')
+ expect(doc.at_css('a')['rel']).to include 'noreferrer'
+ end
-RSpec.describe Banzai::Filter::ExternalLinkFilter do
- include FilterSpecHelper
+ it 'adds rel="noopener" to external links' do
+ expect(doc.at_css('a')).to have_attribute('rel')
+ expect(doc.at_css('a')['rel']).to include 'noopener'
+ end
+ end
it 'ignores elements without an href attribute' do
exp = act = %q(<a id="ignored">Ignore Me</a>)