Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									29a7132039
								
							
						
					
					
						commit
						eca6018a19
					
				|  | @ -1,15 +1,30 @@ | |||
| <script> | ||||
| import MergeRequestsWidget from './merge_requests_widget.vue'; | ||||
| import ActivityWidget from './activity_widget.vue'; | ||||
| import TodosWidget from './todos_widget.vue'; | ||||
| 
 | ||||
| export default { | ||||
|   components: { ActivityWidget, TodosWidget }, | ||||
|   components: { MergeRequestsWidget, ActivityWidget, TodosWidget }, | ||||
|   props: { | ||||
|     reviewRequestedPath: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|     assignedToYouPath: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div> | ||||
|     <h1>{{ __("Today's highlights") }}</h1> | ||||
|     <merge-requests-widget | ||||
|       :review-requested-path="reviewRequestedPath" | ||||
|       :assigned-to-you-path="assignedToYouPath" | ||||
|     /> | ||||
|     <todos-widget /> | ||||
|     <activity-widget /> | ||||
|   </div> | ||||
|  |  | |||
|  | @ -0,0 +1,37 @@ | |||
| <script> | ||||
| import { GlIcon, GlLink } from '@gitlab/ui'; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'MergeRequestsWidget', | ||||
|   components: { | ||||
|     GlIcon, | ||||
|     GlLink, | ||||
|   }, | ||||
|   props: { | ||||
|     reviewRequestedPath: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|     assignedToYouPath: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div class="gl-border gl-rounded-lg gl-px-4 gl-py-1"> | ||||
|     <h4 class="gl-flex gl-items-center gl-gap-2"> | ||||
|       <gl-icon name="merge-request" :size="16" />{{ __('Merge requests') }} | ||||
|     </h4> | ||||
|     <ul class="gl-list-none gl-p-0"> | ||||
|       <li> | ||||
|         <gl-link :href="reviewRequestedPath">{{ __('Review requested') }}</gl-link> | ||||
|       </li> | ||||
|       <li> | ||||
|         <gl-link :href="assignedToYouPath">{{ __('Assigned to you') }}</gl-link> | ||||
|       </li> | ||||
|     </ul> | ||||
|   </div> | ||||
| </template> | ||||
|  | @ -12,13 +12,20 @@ export default () => { | |||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   const { reviewRequestedPath, assignedToYouPath } = el.dataset; | ||||
| 
 | ||||
|   return new Vue({ | ||||
|     el, | ||||
|     apolloProvider: new VueApollo({ | ||||
|       defaultClient: createDefaultClient(), | ||||
|     }), | ||||
|     render(createElement) { | ||||
|       return createElement(HomepageApp); | ||||
|       return createElement(HomepageApp, { | ||||
|         props: { | ||||
|           reviewRequestedPath, | ||||
|           assignedToYouPath, | ||||
|         }, | ||||
|       }); | ||||
|     }, | ||||
|   }); | ||||
| }; | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { GlToast } from '@gitlab/ui'; | ||||
| import Vue from 'vue'; | ||||
| import { groupsProvideData } from 'ee_else_ce/invite_members/utils'; | ||||
| import InviteGroupsModal from '~/invite_members/components/invite_groups_modal.vue'; | ||||
| import { parseBoolean } from '~/lib/utils/common_utils'; | ||||
| 
 | ||||
|  | @ -28,12 +29,7 @@ export default function initInviteGroupsModal() { | |||
| 
 | ||||
|   return new Vue({ | ||||
|     el, | ||||
|     provide: { | ||||
|       freeUsersLimit: parseInt(el.dataset.freeUsersLimit, 10), | ||||
|       overageMembersModalAvailable: parseBoolean(el.dataset.overageMembersModalAvailable), | ||||
|       hasGitlabSubscription: parseBoolean(el.dataset.hasGitlabSubscription), | ||||
|       inviteWithCustomRoleEnabled: parseBoolean(el.dataset.inviteWithCustomRoleEnabled), | ||||
|     }, | ||||
|     provide: groupsProvideData(el), | ||||
|     render: (createElement) => | ||||
|       createElement(InviteGroupsModal, { | ||||
|         props: { | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { GlToast } from '@gitlab/ui'; | ||||
| import Vue from 'vue'; | ||||
| import { membersProvideData } from 'ee_else_ce/invite_members/utils'; | ||||
| import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue'; | ||||
| import { parseBoolean, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; | ||||
| 
 | ||||
|  | @ -23,14 +24,7 @@ export default (function initInviteMembersModal() { | |||
|       inviteMembersModal = new Vue({ | ||||
|         el, | ||||
|         name: 'InviteMembersModalRoot', | ||||
|         provide: { | ||||
|           name: el.dataset.name, | ||||
|           overageMembersModalAvailable: parseBoolean(el.dataset.overageMembersModalAvailable), | ||||
|           hasGitlabSubscription: parseBoolean(el.dataset.hasGitlabSubscription), | ||||
|           addSeatsHref: el.dataset.addSeatsHref, | ||||
|           hasBsoEnabled: parseBoolean(el.dataset.hasBsoFeatureEnabled), | ||||
|           searchUrl: el.dataset.searchUrl, | ||||
|         }, | ||||
|         provide: membersProvideData(el), | ||||
|         render: (createElement) => | ||||
|           createElement(InviteMembersModal, { | ||||
|             props: { | ||||
|  |  | |||
|  | @ -0,0 +1,45 @@ | |||
| import { parseBoolean } from '~/lib/utils/common_utils'; | ||||
| 
 | ||||
| export function membersProvideData(el) { | ||||
|   if (!el) { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   const { | ||||
|     name, | ||||
|     overageMembersModalAvailable, | ||||
|     hasGitlabSubscription, | ||||
|     addSeatsHref, | ||||
|     hasBsoFeatureEnabled, | ||||
|     searchUrl, | ||||
|   } = el.dataset; | ||||
| 
 | ||||
|   return { | ||||
|     name, | ||||
|     overageMembersModalAvailable: parseBoolean(overageMembersModalAvailable), | ||||
|     hasGitlabSubscription: parseBoolean(hasGitlabSubscription), | ||||
|     addSeatsHref, | ||||
|     hasBsoEnabled: parseBoolean(hasBsoFeatureEnabled), | ||||
|     searchUrl, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function groupsProvideData(el) { | ||||
|   if (!el) { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   const { | ||||
|     freeUsersLimit, | ||||
|     overageMembersModalAvailable, | ||||
|     hasGitlabSubscription, | ||||
|     inviteWithCustomRoleEnabled, | ||||
|   } = el.dataset; | ||||
| 
 | ||||
|   return { | ||||
|     freeUsersLimit: parseInt(freeUsersLimit, 10), | ||||
|     overageMembersModalAvailable: parseBoolean(overageMembersModalAvailable), | ||||
|     hasGitlabSubscription: parseBoolean(hasGitlabSubscription), | ||||
|     inviteWithCustomRoleEnabled: parseBoolean(inviteWithCustomRoleEnabled), | ||||
|   }; | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module HomepageData | ||||
|   extend ActiveSupport::Concern | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def homepage_app_data(user) | ||||
|     { | ||||
|       review_requested_path: merge_requests_dashboard_path(reviewer_username: user.username), | ||||
|       assigned_to_you_path: merge_requests_dashboard_path(assignee_username: user.username) | ||||
|     } | ||||
|   end | ||||
| end | ||||
|  | @ -9,6 +9,8 @@ | |||
| # For users who haven't customized the setting, we simply delegate to | ||||
| # `DashboardController#show`, which is the default. | ||||
| class RootController < Dashboard::ProjectsController | ||||
|   include HomepageData | ||||
| 
 | ||||
|   skip_before_action :authenticate_user!, only: [:index] | ||||
| 
 | ||||
|   before_action :redirect_unlogged_user, if: -> { current_user.nil? } | ||||
|  | @ -21,6 +23,7 @@ class RootController < Dashboard::ProjectsController | |||
|   CACHE_CONTROL_HEADER = 'no-store' | ||||
| 
 | ||||
|   def index | ||||
|     @homepage_app_data = @current_user.nil? ? {} : homepage_app_data(@current_user) | ||||
|     render('root/index') && return if Feature.enabled?(:personal_homepage, current_user) | ||||
| 
 | ||||
|     super | ||||
|  |  | |||
|  | @ -1562,8 +1562,10 @@ class Project < ApplicationRecord | |||
|   end | ||||
| 
 | ||||
|   def merge_base_commit(first_commit_id, second_commit_id) | ||||
|     sha = repository.merge_base(first_commit_id, second_commit_id) | ||||
|     commit_by(oid: sha) if sha | ||||
|     strong_memoize(:"merge_base_commit_#{first_commit_id}_#{second_commit_id}") do | ||||
|       sha = repository.merge_base(first_commit_id, second_commit_id) | ||||
|       commit_by(oid: sha) if sha | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def saved? | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| - page_title _("Home") | ||||
| 
 | ||||
| #js-homepage-app | ||||
| #js-homepage-app{ data: @homepage_app_data } | ||||
|  |  | |||
|  | @ -142,6 +142,7 @@ To impersonate a user: | |||
|   1. On the left sidebar, select **Overview > Users**. | ||||
|   1. From the list of users, select a user. | ||||
|   1. On the top right, select **Impersonate**. | ||||
|   1. To stop impersonating, on the left sidebar at the top, select **Stop impersonating** ({{< icon name="incognito">}}). | ||||
| - With the API, using [impersonation tokens](../api/rest/authentication.md#impersonation-tokens). | ||||
| 
 | ||||
| All impersonation activities are [captured with audit events](compliance/audit_event_reports.md#user-impersonation). | ||||
|  |  | |||
|  | @ -349,7 +349,7 @@ use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to | |||
|     ... | ||||
|     computed: { | ||||
|       userWelcome() { | ||||
|         sprintf(__('Hello %{username}'), { username: this.user.name }); | ||||
|         return sprintf(__('Hello %{username}'), { username: this.user.name }); | ||||
|       } | ||||
|     } | ||||
|     ... | ||||
|  |  | |||
|  | @ -18,11 +18,11 @@ module Gitlab | |||
|         GLAB_WARNING_MESSAGE = "Warning: release-cli will not be supported after 19.0. Please use glab version >= #{GLAB_REQUIRED_VERSION}. Troubleshooting: #{TROUBLESHOOTING_URL}".freeze | ||||
| 
 | ||||
|         GLAB_ENV_SET_UNIX = 'export GITLAB_HOST=$CI_SERVER_URL' | ||||
|         GLAB_ENV_SET_WINDOWS = '$env:GITLAB_HOST = $env:CI_SERVER_URL' | ||||
|         GLAB_ENV_SET_WINDOWS = '$$env:GITLAB_HOST = $$env:CI_SERVER_URL' | ||||
|         GLAB_LOGIN_UNIX = 'glab auth login --job-token $CI_JOB_TOKEN --hostname "$CI_SERVER_FQDN" --api-protocol $CI_SERVER_PROTOCOL' | ||||
|         GLAB_LOGIN_WINDOWS = 'glab auth login --job-token $env:CI_JOB_TOKEN --hostname "$env:CI_SERVER_FQDN" --api-protocol $env:CI_SERVER_PROTOCOL' | ||||
|         GLAB_LOGIN_WINDOWS = 'glab auth login --job-token $$env:CI_JOB_TOKEN --hostname "$$env:CI_SERVER_FQDN" --api-protocol $$env:CI_SERVER_PROTOCOL' | ||||
|         GLAB_CREATE_UNIX = 'glab release create -R $CI_PROJECT_PATH' | ||||
|         GLAB_CREATE_WINDOWS = 'glab release create -R $env:CI_PROJECT_PATH' | ||||
|         GLAB_CREATE_WINDOWS = 'glab release create -R $$env:CI_PROJECT_PATH' | ||||
|         GLAB_PUBLISH_TO_CATALOG_FLAG = '--publish-to-catalog' # enables publishing to the catalog after creating the release | ||||
|         GLAB_NO_UPDATE_FLAG = '--no-update' # disables updating the release if it already exists | ||||
|         GLAB_NO_CLOSE_MILESTONE_FLAG = '--no-close-milestone' # disables closing the milestone after creating the release | ||||
|  | @ -42,11 +42,11 @@ module Gitlab | |||
|           fi | ||||
|         BASH | ||||
|         GLAB_CA_CERT_CONFIG_WINDOWS = <<~POWERSHELL.chomp.freeze | ||||
|           if ($env:ADDITIONAL_CA_CERT_BUNDLE) { | ||||
|             Write-Output "Setting CA certificate for $env:CI_SERVER_FQDN" | ||||
|           if ($$env:ADDITIONAL_CA_CERT_BUNDLE) { | ||||
|             Write-Output "Setting CA certificate for $$env:CI_SERVER_FQDN" | ||||
| 
 | ||||
|             "$env:ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}" | ||||
|             glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$env:CI_SERVER_FQDN" | ||||
|             "$$env:ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}" | ||||
|             glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$$env:CI_SERVER_FQDN" | ||||
|           } | ||||
|         POWERSHELL | ||||
|         GLAB_CA_CERT_CLEANUP_WINDOWS = <<~POWERSHELL.chomp.freeze | ||||
|  | @ -92,10 +92,10 @@ module Gitlab | |||
|         def glab_windows_script | ||||
|           <<~POWERSHELL | ||||
|           if (Get-Command glab -ErrorAction SilentlyContinue) { | ||||
|             $glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
|             $$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
| 
 | ||||
|             if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|               if ([version]$matches[1] -ge [version]"#{GLAB_REQUIRED_VERSION}") { | ||||
|             if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|               if ([version]$$matches[1] -ge [version]"#{GLAB_REQUIRED_VERSION}") { | ||||
|                 #{GLAB_ENV_SET_WINDOWS} | ||||
|                 #{GLAB_CA_CERT_CONFIG_WINDOWS} | ||||
|                 #{GLAB_LOGIN_WINDOWS} | ||||
|  | @ -159,8 +159,8 @@ module Gitlab | |||
|             command = GLAB_CREATE_WINDOWS.dup | ||||
| 
 | ||||
|             # More information: https://gitlab.com/groups/gitlab-org/-/epics/15437#note_2432564707 | ||||
|             tag_name = config[:tag_name].presence || '$env:CI_COMMIT_TAG' | ||||
|             ref = config[:ref].presence || '$env:CI_COMMIT_SHA' | ||||
|             tag_name = config[:tag_name].presence || '$$env:CI_COMMIT_TAG' | ||||
|             ref = config[:ref].presence || '$$env:CI_COMMIT_SHA' | ||||
|           else | ||||
|             command = GLAB_CREATE_UNIX.dup | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,22 @@ module Gitlab | |||
|         Gitlab::Routing.url_helpers.help_page_path('ci/variables/_index.md', anchor: 'define-a-cicd-variable-in-the-ui') | ||||
|       end | ||||
| 
 | ||||
|       def self.vulnerability_checks_documentation_link | ||||
|         Gitlab::Routing.url_helpers.help_page_path('user/application_security/dast/browser/checks/_index.md') | ||||
|       end | ||||
| 
 | ||||
|       def self.secure_log_level_documentation_link | ||||
|         Gitlab::Routing.url_helpers.help_page_path('user/application_security/dast/browser/troubleshooting.md', | ||||
|           anchor: 'secure_log_level') | ||||
|       end | ||||
| 
 | ||||
|       def self.authentication_actions_documentation_link | ||||
|         Gitlab::Routing.url_helpers.help_page_path( | ||||
|           'user/application_security/dast/browser/configuration/authentication.md', | ||||
|           anchor: 'taking-additional-actions-after-submitting-the-login-form' | ||||
|         ) | ||||
|       end | ||||
| 
 | ||||
|       # rubocop: disable Metrics/AbcSize -- Generate dynamic translation as per | ||||
|       # https://docs.gitlab.com/ee/development/i18n/externalization.html#keep-translations-dynamic | ||||
|       def self.data | ||||
|  | @ -35,11 +51,11 @@ module Gitlab | |||
|               type: "string", | ||||
|               example: "select(option=id:accept-yes),click(on=css:.continue)", | ||||
|               name: s_("DastProfiles|After-login actions"), | ||||
|               description: s_( | ||||
|               description: format(s_( | ||||
|                 "DastProfiles|A comma-separated list of actions to take after login but before login verification. " \ | ||||
|                   "Supports `click` and `select` actions. " \ | ||||
|                   "See [Taking additional actions after submitting the login form]" \ | ||||
|                   "(authentication.md#taking-additional-actions-after-submitting-the-login-form)." | ||||
|                   "See [Taking additional actions after submitting the login form](%{documentation_link})."), | ||||
|                 documentation_link: authentication_actions_documentation_link | ||||
|               ) | ||||
|             }, | ||||
|             DAST_AUTH_BEFORE_LOGIN_ACTIONS: { | ||||
|  | @ -519,6 +535,7 @@ module Gitlab | |||
|           }, | ||||
|           scanner: { | ||||
|             DAST_AUTH_REPORT: { | ||||
|               additional: true, | ||||
|               auth: true, | ||||
|               type: "boolean", | ||||
|               example: true, | ||||
|  | @ -531,24 +548,29 @@ module Gitlab | |||
|               ) | ||||
|             }, | ||||
|             DAST_CHECKS_TO_EXCLUDE: { | ||||
|               additional: true, | ||||
|               type: "string", | ||||
|               example: "552.2,78.1", | ||||
|               name: s_("DastProfiles|Excluded checks"), | ||||
|               description: s_( | ||||
|               description: format(s_( | ||||
|                 "DastProfiles|Comma-separated list of check identifiers to exclude from the scan. " \ | ||||
|                   "For identifiers, see [vulnerability checks](../checks/_index.md)." | ||||
|                   "For identifiers, see [vulnerability checks](%{documentation_link})."), | ||||
|                 documentation_link: vulnerability_checks_documentation_link | ||||
|               ) | ||||
|             }, | ||||
|             DAST_CHECKS_TO_RUN: { | ||||
|               additional: true, | ||||
|               type: "List of strings", | ||||
|               example: "16.1,16.2,16.3", | ||||
|               name: s_("DastProfiles|Included checks"), | ||||
|               description: s_( | ||||
|               description: format(s_( | ||||
|                 "DastProfiles|Comma-separated list of check identifiers to use for the scan. " \ | ||||
|                   "For identifiers, see [vulnerability checks](../checks/_index.md)." | ||||
|                   "For identifiers, see [vulnerability checks](%{documentation_link})."), | ||||
|                 documentation_link: vulnerability_checks_documentation_link | ||||
|               ) | ||||
|             }, | ||||
|             DAST_CRAWL_GRAPH: { | ||||
|               additional: true, | ||||
|               type: "boolean", | ||||
|               example: true, | ||||
|               name: s_("DastProfiles|Generate graph"), | ||||
|  | @ -559,18 +581,21 @@ module Gitlab | |||
|               ) | ||||
|             }, | ||||
|             DAST_FULL_SCAN: { | ||||
|               additional: true, | ||||
|               type: "boolean", | ||||
|               example: true, | ||||
|               name: s_("DastProfiles|Full scan"), | ||||
|               description: s_("DastProfiles|Set to `true` to run both passive and active checks. Default is `false`.") | ||||
|             }, | ||||
|             DAST_LOG_BROWSER_OUTPUT: { | ||||
|               additional: true, | ||||
|               type: "boolean", | ||||
|               example: true, | ||||
|               name: s_("DastProfiles|Log browser output"), | ||||
|               description: s_("DastProfiles|Set to `true` to log Chromium `STDOUT` and `STDERR`.") | ||||
|             }, | ||||
|             DAST_LOG_CONFIG: { | ||||
|               additional: true, | ||||
|               type: "List of strings", | ||||
|               example: "brows:debug,auth:debug", | ||||
|               name: s_("DastProfiles|Log levels"), | ||||
|  | @ -578,12 +603,14 @@ module Gitlab | |||
|                 "DastProfiles|A list of modules and their intended logging level for use in the console log.") | ||||
|             }, | ||||
|             DAST_LOG_DEVTOOLS_CONFIG: { | ||||
|               additional: true, | ||||
|               type: "string", | ||||
|               example: "Default:messageAndBody,truncate:2000", | ||||
|               name: s_("DastProfiles|Log messages"), | ||||
|               description: s_("DastProfiles|Set to log protocol messages between DAST and the Chromium browser.") | ||||
|             }, | ||||
|             DAST_LOG_FILE_CONFIG: { | ||||
|               additional: true, | ||||
|               type: "List of strings", | ||||
|               example: "brows:debug,auth:debug", | ||||
|               name: s_("DastProfiles|Log file levels"), | ||||
|  | @ -591,24 +618,28 @@ module Gitlab | |||
|                 "DastProfiles|A list of modules and their intended logging level for use in the file log.") | ||||
|             }, | ||||
|             DAST_LOG_FILE_PATH: { | ||||
|               additional: true, | ||||
|               type: "string", | ||||
|               example: "/output/browserker.log", | ||||
|               name: s_("DastProfiles|Log file path"), | ||||
|               description: s_("DastProfiles|Set to the path of the file log. Default is `gl-dast-scan.log`.") | ||||
|             }, | ||||
|             SECURE_ANALYZERS_PREFIX: { | ||||
|               additional: true, | ||||
|               type: "URL", | ||||
|               example: "registry.organization.com", | ||||
|               name: s_("DastProfiles|Docker registry"), | ||||
|               description: s_("DastProfiles|Set the Docker registry base address from which to download the analyzer.") | ||||
|             }, | ||||
|             SECURE_LOG_LEVEL: { | ||||
|               additional: true, | ||||
|               type: "string", | ||||
|               example: "debug", | ||||
|               name: s_("DastProfiles|Default log level"), | ||||
|               description: s_( | ||||
|               description: format(s_( | ||||
|                 "DastProfiles|Set the default level for the file log. " \ | ||||
|                   "See [SECURE_LOG_LEVEL](../troubleshooting.md#secure_log_level)." \ | ||||
|                   "See [SECURE_LOG_LEVEL](%{documentation_link})."), | ||||
|                 documentation_link: secure_log_level_documentation_link | ||||
|               ) | ||||
|             } | ||||
|           } | ||||
|  | @ -617,7 +648,7 @@ module Gitlab | |||
|       # rubocop: enable Metrics/AbcSize | ||||
| 
 | ||||
|       def self.additional_site_variables | ||||
|         data[:site].filter { |_, variable| variable[:additional] } | ||||
|         data[:site].merge(data[:scanner]).filter { |_, variable| variable[:additional] } | ||||
|       end | ||||
| 
 | ||||
|       def self.auth_variables | ||||
|  |  | |||
|  | @ -136,6 +136,9 @@ module Gitlab | |||
|         end | ||||
| 
 | ||||
|         def emitter_class | ||||
|           # Use test emitter in test environment to prevent HTTP requests | ||||
|           return SnowplowTestEmitter if Rails.env.test? | ||||
| 
 | ||||
|           # snowplow_enabled? is true for gitlab.com and customers that configured their own Snowplow collector | ||||
|           # In both bases we do not want to log the events being sent as the instance is controlled by the same company | ||||
|           # controlling the Snowplow collector. | ||||
|  |  | |||
|  | @ -0,0 +1,16 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module Gitlab | ||||
|   module Tracking | ||||
|     class SnowplowTestEmitter < SnowplowTracker::Emitter | ||||
|       extend ::Gitlab::Utils::Override | ||||
| 
 | ||||
|       # Override send_requests to prevent HTTP requests in test environment | ||||
|       # This allows event tracking to work normally without making actual HTTP calls | ||||
|       override :send_requests | ||||
|       def send_requests(events) | ||||
|         events.size | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -19978,7 +19978,7 @@ msgstr "" | |||
| msgid "DastProfiles|A URL that is compared to the URL in the browser to determine if authentication has succeeded after the login form is submitted." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|A comma-separated list of actions to take after login but before login verification. Supports `click` and `select` actions. See [Taking additional actions after submitting the login form](authentication.md#taking-additional-actions-after-submitting-the-login-form)." | ||||
| msgid "DastProfiles|A comma-separated list of actions to take after login but before login verification. Supports `click` and `select` actions. See [Taking additional actions after submitting the login form](%{documentation_link})." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|A comma-separated list of selectors representing elements to click on prior to entering the DAST_AUTH_USERNAME and DAST_AUTH_PASSWORD into the login form." | ||||
|  | @ -20086,10 +20086,10 @@ msgstr "" | |||
| msgid "DastProfiles|Clear input fields" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|Comma-separated list of check identifiers to exclude from the scan. For identifiers, see [vulnerability checks](../checks/_index.md)." | ||||
| msgid "DastProfiles|Comma-separated list of check identifiers to exclude from the scan. For identifiers, see [vulnerability checks](%{documentation_link})." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|Comma-separated list of check identifiers to use for the scan. For identifiers, see [vulnerability checks](../checks/_index.md)." | ||||
| msgid "DastProfiles|Comma-separated list of check identifiers to use for the scan. For identifiers, see [vulnerability checks](%{documentation_link})." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|Comma-separated list of selectors that are ignored when scanning." | ||||
|  | @ -20434,7 +20434,7 @@ msgstr "" | |||
| msgid "DastProfiles|Set the Docker registry base address from which to download the analyzer." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|Set the default level for the file log. See [SECURE_LOG_LEVEL](../troubleshooting.md#secure_log_level)." | ||||
| msgid "DastProfiles|Set the default level for the file log. See [SECURE_LOG_LEVEL](%{documentation_link})." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DastProfiles|Set to `false` to disable caching. Default: `true`. **Note**: Disabling cache can cause OOM events or DAST job timeouts." | ||||
|  | @ -23325,6 +23325,27 @@ msgstr "" | |||
| msgid "Duo Workflow|Something went wrong saving Duo Workflow settings" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|Agents" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|Failed to fetch workflows" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|Last updated" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|New Agent runs will appear here." | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|No Agent runs yet" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|Prompt" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoAgentsPlatform|Status" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "DuoChat|%{linkStart}Learn how%{linkEnd} to set up Code Suggestions and Chat in your IDE. You can also use Chat in GitLab. Ask questions about:" | ||||
| msgstr "" | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,32 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import HomepageApp from '~/homepage/components/homepage_app.vue'; | ||||
| import MergeRequestsWidget from '~/homepage/components/merge_requests_widget.vue'; | ||||
| 
 | ||||
| describe('HomepageApp', () => { | ||||
|   const MOCK_REVIEW_REQUESTED_PATH = '/review/requested/path'; | ||||
|   const MOCK_ASSIGNED_TO_YOU_PATH = '/assigned/to/you/path'; | ||||
| 
 | ||||
|   let wrapper; | ||||
| 
 | ||||
|   const findMergeRequestsWidget = () => wrapper.findComponent(MergeRequestsWidget); | ||||
| 
 | ||||
|   function createWrapper() { | ||||
|     wrapper = shallowMount(HomepageApp, { | ||||
|       propsData: { | ||||
|         reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH, | ||||
|         assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH, | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     createWrapper(); | ||||
|   }); | ||||
| 
 | ||||
|   it('passes the correct props to the `MergeRequestsWidget` component', () => { | ||||
|     expect(findMergeRequestsWidget().props()).toEqual({ | ||||
|       reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH, | ||||
|       assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH, | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|  | @ -0,0 +1,33 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import { GlLink } from '@gitlab/ui'; | ||||
| import MergeRequestsWidget from '~/homepage/components/merge_requests_widget.vue'; | ||||
| 
 | ||||
| describe('MergeRequestsWidget', () => { | ||||
|   const MOCK_REVIEW_REQUESTED_PATH = '/review/requested/path'; | ||||
|   const MOCK_ASSIGNED_TO_YOU_PATH = '/assigned/to/you/path'; | ||||
| 
 | ||||
|   let wrapper; | ||||
| 
 | ||||
|   const findGlLinks = () => wrapper.findAllComponents(GlLink); | ||||
| 
 | ||||
|   function createWrapper() { | ||||
|     wrapper = shallowMount(MergeRequestsWidget, { | ||||
|       propsData: { | ||||
|         reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH, | ||||
|         assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH, | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     createWrapper(); | ||||
|   }); | ||||
| 
 | ||||
|   it('renders the "Review requested" link', () => { | ||||
|     expect(findGlLinks().at(0).props('href')).toBe(MOCK_REVIEW_REQUESTED_PATH); | ||||
|   }); | ||||
| 
 | ||||
|   it('renders the "Assigned to you" link', () => { | ||||
|     expect(findGlLinks().at(1).props('href')).toBe(MOCK_ASSIGNED_TO_YOU_PATH); | ||||
|   }); | ||||
| }); | ||||
|  | @ -22,7 +22,7 @@ RSpec.describe InviteMembersHelper do | |||
|         help_link: help_page_url('user/permissions.md'), | ||||
|         is_project: 'true', | ||||
|         access_levels: ProjectMember.access_level_roles.to_json, | ||||
|         full_path: project.full_path | ||||
|         full_path: Gitlab.ee? ? project.root_ancestor.full_path : project.full_path | ||||
|       } | ||||
| 
 | ||||
|       expect(helper.common_invite_group_modal_data(project, ProjectMember)).to include(attributes) | ||||
|  | @ -60,7 +60,7 @@ RSpec.describe InviteMembersHelper do | |||
|         root_id: project.root_ancestor.id, | ||||
|         name: project.name, | ||||
|         default_access_level: Gitlab::Access::GUEST, | ||||
|         full_path: project.full_path | ||||
|         full_path: Gitlab.ee? ? project.root_ancestor.full_path : project.full_path | ||||
|       } | ||||
| 
 | ||||
|       expect(helper.common_invite_modal_dataset(project)).to include(attributes) | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr | |||
|       result_for_release_cli_without_catalog_publish = "#{release_cli_command} #{release_cli_assets_links}" | ||||
| 
 | ||||
|       glab_create_unix = 'glab release create -R $CI_PROJECT_PATH' | ||||
|       glab_create_windows = 'glab release create -R $env:CI_PROJECT_PATH' | ||||
|       glab_create_windows = 'glab release create -R $$env:CI_PROJECT_PATH' | ||||
|       glab_command = "\"release-$CI_COMMIT_SHA\" #{glab_assets_links} --milestone \"m1,m2,m3\" --name \"Release $CI_COMMIT_SHA\" --experimental-notes-text-or-file \"Created using the release-cli $EXTRA_DESCRIPTION\" --ref \"$CI_COMMIT_SHA\" --tag-message \"Annotated tag message\" --released-at \"2020-07-15T08:00:00Z\" --no-update --no-close-milestone" | ||||
| 
 | ||||
|       warning_message = "Warning: release-cli will not be supported after 19.0. Please use glab version >= #{described_class::GLAB_REQUIRED_VERSION}. Troubleshooting: http://localhost/help/user/project/releases/_index.md#gitlab-cli-version-requirement" | ||||
|  | @ -66,10 +66,10 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr | |||
|       BASH | ||||
|       windows_result_for_glab_or_release_cli_without_catalog_publish = <<~POWERSHELL | ||||
|       if (Get-Command glab -ErrorAction SilentlyContinue) { | ||||
|         $glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
|         $$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
| 
 | ||||
|         if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|           if ([version]$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") { | ||||
|         if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|           if ([version]$$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") { | ||||
|             #{described_class::GLAB_ENV_SET_WINDOWS} | ||||
|             #{described_class::GLAB_CA_CERT_CONFIG_WINDOWS} | ||||
|             #{described_class::GLAB_LOGIN_WINDOWS} | ||||
|  | @ -145,10 +145,10 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr | |||
|         BASH | ||||
|         windows_result_for_glab_or_release_cli_with_catalog_publish = <<~POWERSHELL | ||||
|         if (Get-Command glab -ErrorAction SilentlyContinue) { | ||||
|           $glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
|           $$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string] | ||||
| 
 | ||||
|           if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|             if ([version]$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") { | ||||
|           if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') { | ||||
|             if ([version]$$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") { | ||||
|               #{described_class::GLAB_ENV_SET_WINDOWS} | ||||
|               #{described_class::GLAB_CA_CERT_CONFIG_WINDOWS} | ||||
|               #{described_class::GLAB_LOGIN_WINDOWS} | ||||
|  |  | |||
|  | @ -6,9 +6,15 @@ RSpec.describe ::Gitlab::Security::DastVariables, feature_category: :dynamic_app | |||
|   let(:dast_variables) { described_class } | ||||
| 
 | ||||
|   describe '#additional_site_variables' do | ||||
|     it 'contains only additional variables' do | ||||
|       described_class.additional_site_variables.each_value do |variable| | ||||
|         expect(variable[:additional]).to be(true) | ||||
|     [:site, :scanner].each do |type| | ||||
|       it "contains additional #{type} variables" do | ||||
|         described_class.data[type].each do |key, variable| | ||||
|           if variable[:additional] | ||||
|             expect(described_class.additional_site_variables[key]).not_to be_nil | ||||
|           else | ||||
|             expect(described_class.additional_site_variables[key]).to be_nil | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -106,7 +106,11 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   context "when in development or test environment" do | ||||
|   context "when in development environment" do | ||||
|     before do | ||||
|       allow(Rails.env).to receive_messages(test?: false, development?: true) | ||||
|     end | ||||
| 
 | ||||
|     it "initializes POST emitter with buffer_size 1" do | ||||
|       allow(SnowplowTracker::Tracker).to receive(:new).and_return(tracker) | ||||
|       allow(tracker).to receive(:track_struct_event).and_call_original | ||||
|  | @ -174,7 +178,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b | |||
|     let(:payload) { { "event" => "page_view", "user_id" => "123" } } | ||||
| 
 | ||||
|     before do | ||||
|       allow(SnowplowTracker::AsyncEmitter).to receive(:new).and_return(emitter) | ||||
|       allow(Gitlab::Tracking::SnowplowTestEmitter).to receive(:new).and_return(emitter) | ||||
|     end | ||||
| 
 | ||||
|     it "forwards the payload to the emitter" do | ||||
|  | @ -333,6 +337,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b | |||
|     context 'when snowplow is enabled' do | ||||
|       before do | ||||
|         stub_application_setting(snowplow_enabled?: true) | ||||
|         allow(Rails.env).to receive(:test?).and_return(false) | ||||
|       end | ||||
| 
 | ||||
|       it 'uses AsyncEmitter' do | ||||
|  | @ -346,6 +351,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b | |||
|     context 'when snowplow is disabled' do | ||||
|       before do | ||||
|         stub_application_setting(snowplow_enabled?: false) | ||||
|         allow(Rails.env).to receive(:test?).and_return(false) | ||||
|       end | ||||
| 
 | ||||
|       context 'when GITLAB_DISABLE_PRODUCT_USAGE_EVENT_LOGGING env variable is true' do | ||||
|  | @ -379,5 +385,15 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b | |||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'in test environment' do | ||||
|       it 'uses SnowplowTestEmitter to prevent HTTP requests' do | ||||
|         # In test environment, we expect SnowplowTestEmitter to prevent HTTP requests | ||||
|         expect(Gitlab::Tracking::SnowplowTestEmitter).to receive(:new) | ||||
|         expect(SnowplowTracker::AsyncEmitter).not_to receive(:new) | ||||
|         expect(Gitlab::Tracking::SnowplowLoggingEmitter).not_to receive(:new) | ||||
|         subject.send(:emitter) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe Gitlab::Tracking::SnowplowTestEmitter, feature_category: :service_ping do | ||||
|   describe '#send_requests' do | ||||
|     it 'returns the number of events' do | ||||
|       emitter = described_class.new(endpoint: 'test') | ||||
|       events = [{}, {}] | ||||
| 
 | ||||
|       expect(emitter.send_requests(events)).to eq(2) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -10241,4 +10241,16 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr | |||
|       expect(project.valid_lfs_oids(oids)).to eq([lfs_object.oid]) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#merge_base_commit' do | ||||
|     let_it_be(:project) { create(:project, :repository) } | ||||
|     let(:commit1) { project.repository.commit } | ||||
|     let(:commit2) { project.repository.commit('feature') } | ||||
| 
 | ||||
|     it 'memoizes the result' do | ||||
|       expect(project.repository).to receive(:merge_base).once.and_call_original | ||||
| 
 | ||||
|       2.times { project.merge_base_commit(commit1.id, commit2.id) } | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -2,17 +2,9 @@ | |||
| 
 | ||||
| module StubSnowplow | ||||
|   def stub_snowplow | ||||
|     # Using a high buffer size to not cause early flushes | ||||
|     buffer_size = 100 | ||||
|     # WebMock is set up to allow requests to `localhost` | ||||
|     host = 'localhost' | ||||
| 
 | ||||
|     # rubocop:disable RSpec/AnyInstanceOf | ||||
|     allow_any_instance_of(Gitlab::Tracking::Destinations::Snowplow) | ||||
|       .to receive(:emitter) | ||||
|             .and_return(SnowplowTracker::Emitter.new(endpoint: host, options: { buffer_size: buffer_size })) | ||||
|     # rubocop:enable RSpec/AnyInstanceOf | ||||
| 
 | ||||
|     stub_application_setting(snowplow_enabled: true, snowplow_collector_hostname: host) | ||||
| 
 | ||||
|     allow(SnowplowTracker::SelfDescribingJson).to receive(:new).and_call_original | ||||
|  |  | |||
|  | @ -0,0 +1,21 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| RSpec.describe 'root/index.html.haml', feature_category: :onboarding do | ||||
|   let_it_be(:mock_review_requested_path) { "review_requested_path" } | ||||
|   let_it_be(:mock_assigned_to_you_path) { "assigned_to_you_path" } | ||||
| 
 | ||||
|   before do | ||||
|     @homepage_app_data = { | ||||
|       review_requested_path: mock_review_requested_path, | ||||
|       assigned_to_you_path: mock_assigned_to_you_path | ||||
|     } | ||||
|     render | ||||
|   end | ||||
| 
 | ||||
|   it 'renders the app root element with the correct data attributes' do | ||||
|     expect(rendered).to have_css("[data-review-requested-path='#{mock_review_requested_path}']") | ||||
|     expect(rendered).to have_css("[data-assigned-to-you-path='#{mock_assigned_to_you_path}']") | ||||
|   end | ||||
| end | ||||
|  | @ -44,12 +44,25 @@ module Tooling | |||
|         end | ||||
| 
 | ||||
|         def render_description(description) | ||||
|           # replace help_page_path-generated documentation link | ||||
|           # with relative path to documentation file | ||||
|           description.sub( | ||||
|             Gitlab::Security::DastVariables.ci_variables_documentation_link, | ||||
|             '../../../../../ci/variables/_index.md#define-a-cicd-variable-in-the-ui' | ||||
|           ) | ||||
|           # replace help_page_path-generated documentation links | ||||
|           # with relative paths to documentation files | ||||
|           description | ||||
|             .sub( | ||||
|               Gitlab::Security::DastVariables.ci_variables_documentation_link, | ||||
|               '../../../../../ci/variables/_index.md#define-a-cicd-variable-in-the-ui' | ||||
|             ) | ||||
|             .sub( | ||||
|               Gitlab::Security::DastVariables.vulnerability_checks_documentation_link, | ||||
|               '../checks/_index.md' | ||||
|             ) | ||||
|             .sub( | ||||
|               Gitlab::Security::DastVariables.secure_log_level_documentation_link, | ||||
|               '../troubleshooting.md#secure_log_level' | ||||
|             ) | ||||
|             .sub( | ||||
|               Gitlab::Security::DastVariables.authentication_actions_documentation_link, | ||||
|               'authentication.md#taking-additional-actions-after-submitting-the-login-form' | ||||
|             ) | ||||
|         end | ||||
| 
 | ||||
|         def render_row(*values) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue