Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									12fc930567
								
							
						
					
					
						commit
						696edc7f23
					
				|  | @ -12,7 +12,6 @@ Gitlab/FeatureFlagKeyDynamic: | ||||||
|     - 'app/workers/concerns/worker_attributes.rb' |     - 'app/workers/concerns/worker_attributes.rb' | ||||||
|     - 'app/workers/loose_foreign_keys/cleanup_worker.rb' |     - 'app/workers/loose_foreign_keys/cleanup_worker.rb' | ||||||
|     - 'ee/app/graphql/resolvers/ai/user_available_features_resolver.rb' |     - 'ee/app/graphql/resolvers/ai/user_available_features_resolver.rb' | ||||||
|     - 'ee/app/graphql/resolvers/ai/user_code_suggestions_contexts_resolver.rb' |  | ||||||
|     - 'ee/app/models/concerns/geo/verifiable_replicator.rb' |     - 'ee/app/models/concerns/geo/verifiable_replicator.rb' | ||||||
|     - 'ee/app/models/members/member_role.rb' |     - 'ee/app/models/members/member_role.rb' | ||||||
|     - 'ee/app/services/search/zoekt/info_service.rb' |     - 'ee/app/services/search/zoekt/info_service.rb' | ||||||
|  |  | ||||||
|  | @ -4,9 +4,6 @@ Layout/LineBreakAfterFinalMixin: | ||||||
|   Exclude: |   Exclude: | ||||||
|     - 'app/graphql/resolvers/integrations/exclusions_resolver.rb' |     - 'app/graphql/resolvers/integrations/exclusions_resolver.rb' | ||||||
|     - 'app/graphql/resolvers/projects/deploy_key_resolver.rb' |     - 'app/graphql/resolvers/projects/deploy_key_resolver.rb' | ||||||
|     - 'app/models/alert_management/metric_image.rb' |  | ||||||
|     - 'app/models/protected_branch/merge_access_level.rb' |  | ||||||
|     - 'app/models/protected_branch/push_access_level.rb' |  | ||||||
|     - 'app/policies/project_member_policy.rb' |     - 'app/policies/project_member_policy.rb' | ||||||
|     - 'app/serializers/cluster_serializer.rb' |     - 'app/serializers/cluster_serializer.rb' | ||||||
|     - 'app/serializers/container_repositories_serializer.rb' |     - 'app/serializers/container_repositories_serializer.rb' | ||||||
|  | @ -41,21 +38,7 @@ Layout/LineBreakAfterFinalMixin: | ||||||
|     - 'app/workers/stuck_export_jobs_worker.rb' |     - 'app/workers/stuck_export_jobs_worker.rb' | ||||||
|     - 'app/workers/user_status_cleanup/batch_worker.rb' |     - 'app/workers/user_status_cleanup/batch_worker.rb' | ||||||
|     - 'app/workers/users/create_statistics_worker.rb' |     - 'app/workers/users/create_statistics_worker.rb' | ||||||
|     - 'db/migrate/20240213223630_add_duo_features_enabled_cascading_setting.rb' |  | ||||||
|     - 'db/post_migrate/20240419122328_swap_vulnerability_feedback_pipeline_id_convert_to_bigint.rb' |  | ||||||
|     - 'db/post_migrate/20240419131607_swap_packages_build_infos_pipeline_id_convert_to_bigint.rb' |  | ||||||
|     - 'db/post_migrate/20240422080018_swap_merge_trains_pipeline_id_convert_to_bigint.rb' |  | ||||||
|     - 'db/post_migrate/20240424111535_swap_merge_request_metrics_pipeline_id_convert_to_bigint.rb' |  | ||||||
|     - 'db/post_migrate/20240513111937_swap_columns_for_p_ci_builds_trigger_request_and_erased_by.rb' |  | ||||||
|     - 'db/post_migrate/20240514081440_swap_vulnerability_occurrence_pipelines_pipeline_id_convert_to_bigint.rb' |  | ||||||
|     - 'ee/app/controllers/explore/dependencies_controller.rb' |  | ||||||
|     - 'ee/app/finders/security/pipeline_vulnerabilities_finder.rb' |  | ||||||
|     - 'ee/app/graphql/subscriptions/ai_completion_response.rb' |     - 'ee/app/graphql/subscriptions/ai_completion_response.rb' | ||||||
|     - 'ee/app/models/approval_project_rules_protected_branch.rb' |  | ||||||
|     - 'ee/app/models/approval_rules/approval_group_rule.rb' |  | ||||||
|     - 'ee/app/models/approval_rules/approval_group_rules_protected_branch.rb' |  | ||||||
|     - 'ee/app/models/vulnerabilities/scanner.rb' |  | ||||||
|     - 'ee/app/models/vulnerabilities/statistic.rb' |  | ||||||
|     - 'ee/app/services/ee/ip_restrictions/update_service.rb' |     - 'ee/app/services/ee/ip_restrictions/update_service.rb' | ||||||
|     - 'ee/app/services/gitlab_subscriptions/trials/base_apply_trial_service.rb' |     - 'ee/app/services/gitlab_subscriptions/trials/base_apply_trial_service.rb' | ||||||
|     - 'ee/app/services/incident_management/oncall_rotations/edit_service.rb' |     - 'ee/app/services/incident_management/oncall_rotations/edit_service.rb' | ||||||
|  | @ -79,7 +62,6 @@ Layout/LineBreakAfterFinalMixin: | ||||||
|     - 'ee/lib/api/resource_iteration_events.rb' |     - 'ee/lib/api/resource_iteration_events.rb' | ||||||
|     - 'ee/lib/api/resource_weight_events.rb' |     - 'ee/lib/api/resource_weight_events.rb' | ||||||
|     - 'ee/lib/ee/api/entities/project_push_rule.rb' |     - 'ee/lib/ee/api/entities/project_push_rule.rb' | ||||||
|     - 'ee/lib/ee/gitlab/background_migration/create_compliance_standards_adherence.rb' |  | ||||||
|     - 'ee/lib/gitlab/auth/group_saml/identity_linker.rb' |     - 'ee/lib/gitlab/auth/group_saml/identity_linker.rb' | ||||||
|     - 'ee/lib/gitlab/llm/chain/tools/explain_code/prompts/anthropic.rb' |     - 'ee/lib/gitlab/llm/chain/tools/explain_code/prompts/anthropic.rb' | ||||||
|     - 'ee/lib/gitlab/search/zoekt/client.rb' |     - 'ee/lib/gitlab/search/zoekt/client.rb' | ||||||
|  | @ -103,8 +85,6 @@ Layout/LineBreakAfterFinalMixin: | ||||||
|     - 'lib/feature.rb' |     - 'lib/feature.rb' | ||||||
|     - 'lib/gitlab/auth/current_user_mode.rb' |     - 'lib/gitlab/auth/current_user_mode.rb' | ||||||
|     - 'lib/gitlab/auth/otp/strategies/forti_token_cloud.rb' |     - 'lib/gitlab/auth/otp/strategies/forti_token_cloud.rb' | ||||||
|     - 'lib/gitlab/background_migration/backfill_draft_status_on_merge_requests_with_corrected_regex.rb' |  | ||||||
|     - 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb' |  | ||||||
|     - 'lib/gitlab/ci/config/interpolation/config.rb' |     - 'lib/gitlab/ci/config/interpolation/config.rb' | ||||||
|     - 'lib/gitlab/cluster/rack_timeout_observer.rb' |     - 'lib/gitlab/cluster/rack_timeout_observer.rb' | ||||||
|     - 'lib/gitlab/etag_caching/router/graphql.rb' |     - 'lib/gitlab/etag_caching/router/graphql.rb' | ||||||
|  |  | ||||||
|  | @ -142,12 +142,12 @@ export default { | ||||||
|     }, |     }, | ||||||
|     detailsPath() { |     detailsPath() { | ||||||
|       if (this.isLink) { |       if (this.isLink) { | ||||||
|         return this.status.detailsPath; |         return this.status.detailsPath || this.status.deploymentDetailsPath; | ||||||
|       } |       } | ||||||
|       return null; |       return null; | ||||||
|     }, |     }, | ||||||
|     hasDetails() { |     hasDetails() { | ||||||
|       return this.status.hasDetails; |       return this.status.hasDetails || this.status.deploymentDetailsPath; | ||||||
|     }, |     }, | ||||||
|     hasRetryAction() { |     hasRetryAction() { | ||||||
|       return Boolean(this.job?.status?.action?.title === RETRY_ACTION_TITLE); |       return Boolean(this.job?.status?.action?.title === RETRY_ACTION_TITLE); | ||||||
|  | @ -221,7 +221,7 @@ export default { | ||||||
|      * @return {Boolean} |      * @return {Boolean} | ||||||
|      */ |      */ | ||||||
|     hasAction() { |     hasAction() { | ||||||
|       return this.job.status && this.job.status.action && this.job.status.action.path; |       return this.job.status?.action?.path && this.job.status?.action?.icon; | ||||||
|     }, |     }, | ||||||
|     hasManualConfirmationMessage() { |     hasManualConfirmationMessage() { | ||||||
|       return this.job.status.action.confirmationMessage !== null; |       return this.job.status.action.confirmationMessage !== null; | ||||||
|  |  | ||||||
|  | @ -325,7 +325,7 @@ export default { | ||||||
|             @mouseover="setActionTooltip(true)" |             @mouseover="setActionTooltip(true)" | ||||||
|             @mouseout="setActionTooltip(false)" |             @mouseout="setActionTooltip(false)" | ||||||
|           > |           > | ||||||
|             <gl-icon :name="action.icon" size="12" /> |             <gl-icon :name="action.icon" :size="12" /> | ||||||
|           </gl-button> |           </gl-button> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|  |  | ||||||
|  | @ -97,6 +97,7 @@ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .rd-line-number { | .rd-line-number { | ||||||
|  |   position: relative; | ||||||
|   padding: 0 10px 0 5px; |   padding: 0 10px 0 5px; | ||||||
|   text-align: right; |   text-align: right; | ||||||
|   background-color: var(--code-line-nubmer-background-color, $white); |   background-color: var(--code-line-nubmer-background-color, $white); | ||||||
|  | @ -146,6 +147,12 @@ | ||||||
|   &::before { |   &::before { | ||||||
|     content: attr(data-line-number); |     content: attr(data-line-number); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   &::after { | ||||||
|  |     content: ''; | ||||||
|  |     position: absolute; | ||||||
|  |     inset: 0 -1px; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .rd-line-content, | .rd-line-content, | ||||||
|  |  | ||||||
|  | @ -412,8 +412,7 @@ class IssuableFinder | ||||||
|     strong_memoize(:label_filter) do |     strong_memoize(:label_filter) do | ||||||
|       Issuables::LabelFilter.new( |       Issuables::LabelFilter.new( | ||||||
|         params: original_params, |         params: original_params, | ||||||
|         project: params.project, |         parent: params.parent | ||||||
|         group: params.group |  | ||||||
|       ) |       ) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | @ -493,15 +492,19 @@ class IssuableFinder | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def by_crm_contact(items) |   def by_crm_contact(items) | ||||||
|     return items unless can_filter_by_crm_contact? |     Issuables::CrmContactFilter.new( | ||||||
| 
 |       params: original_params, | ||||||
|     Issuables::CrmContactFilter.new(params: original_params).filter(items) |       parent: params.parent, | ||||||
|  |       current_user: current_user | ||||||
|  |     ).filter(items) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def by_crm_organization(items) |   def by_crm_organization(items) | ||||||
|     return items unless can_filter_by_crm_organization? |     Issuables::CrmOrganizationFilter.new( | ||||||
| 
 |       params: original_params, | ||||||
|     Issuables::CrmOrganizationFilter.new(params: original_params).filter(items) |       parent: params.parent, | ||||||
|  |       current_user: current_user | ||||||
|  |     ).filter(items) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def by_subscribed(items) |   def by_subscribed(items) | ||||||
|  | @ -516,18 +519,4 @@ class IssuableFinder | ||||||
|       items |       items | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 |  | ||||||
|   def can_filter_by_crm_contact? |  | ||||||
|     current_user&.can?(:read_crm_contact, crm_group) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def can_filter_by_crm_organization? |  | ||||||
|     current_user&.can?(:read_crm_organization, crm_group) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   def crm_group |  | ||||||
|     strong_memoize(:crm_group) do |  | ||||||
|       params.group&.crm_group || params.project&.crm_group |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -2,13 +2,13 @@ | ||||||
| 
 | 
 | ||||||
| module Issuables | module Issuables | ||||||
|   class BaseFilter |   class BaseFilter | ||||||
|     attr_reader :params |  | ||||||
| 
 |  | ||||||
|     FILTER_NONE = 'none' |     FILTER_NONE = 'none' | ||||||
|     FILTER_ANY = 'any' |     FILTER_ANY = 'any' | ||||||
| 
 | 
 | ||||||
|     def initialize(params:) |     def initialize(params:, parent: nil, current_user: nil) | ||||||
|       @params = params |       @params = params | ||||||
|  |       @parent = parent | ||||||
|  |       @current_user = current_user | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def filter |     def filter | ||||||
|  | @ -17,6 +17,8 @@ module Issuables | ||||||
| 
 | 
 | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|  |     attr_reader :params, :parent, :current_user | ||||||
|  | 
 | ||||||
|     def or_params |     def or_params | ||||||
|       params[:or] |       params[:or] | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ module Issuables | ||||||
|     # rubocop: disable CodeReuse/ActiveRecord |     # rubocop: disable CodeReuse/ActiveRecord | ||||||
|     def by_crm_contact(issuables) |     def by_crm_contact(issuables) | ||||||
|       return issuables if params[:crm_contact_id].blank? |       return issuables if params[:crm_contact_id].blank? | ||||||
|  |       return issuables unless current_user&.can?(:read_crm_contact, parent&.crm_group) | ||||||
| 
 | 
 | ||||||
|       condition = CustomerRelations::IssueContact |       condition = CustomerRelations::IssueContact | ||||||
|         .where(contact_id: params[:crm_contact_id]) |         .where(contact_id: params[:crm_contact_id]) | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ module Issuables | ||||||
|     # rubocop: disable CodeReuse/ActiveRecord |     # rubocop: disable CodeReuse/ActiveRecord | ||||||
|     def by_crm_organization(issuables) |     def by_crm_organization(issuables) | ||||||
|       return issuables if params[:crm_organization_id].blank? |       return issuables if params[:crm_organization_id].blank? | ||||||
|  |       return issuables unless current_user&.can?(:read_crm_organization, parent&.crm_group) | ||||||
| 
 | 
 | ||||||
|       condition = CustomerRelations::IssueContact |       condition = CustomerRelations::IssueContact | ||||||
|         .joins(:contact) |         .joins(:contact) | ||||||
|  |  | ||||||
|  | @ -5,13 +5,6 @@ module Issuables | ||||||
|     include Gitlab::Utils::StrongMemoize |     include Gitlab::Utils::StrongMemoize | ||||||
|     extend Gitlab::Cache::RequestCache |     extend Gitlab::Cache::RequestCache | ||||||
| 
 | 
 | ||||||
|     def initialize(project:, group:, **kwargs) |  | ||||||
|       @project = project |  | ||||||
|       @group = group |  | ||||||
| 
 |  | ||||||
|       super(**kwargs) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def filter(issuables) |     def filter(issuables) | ||||||
|       filtered = by_label(issuables) |       filtered = by_label(issuables) | ||||||
|       filtered = by_label_union(filtered) |       filtered = by_label_union(filtered) | ||||||
|  | @ -40,8 +33,6 @@ module Issuables | ||||||
| 
 | 
 | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|     attr_reader :project, :group |  | ||||||
| 
 |  | ||||||
|     # rubocop: disable CodeReuse/ActiveRecord |     # rubocop: disable CodeReuse/ActiveRecord | ||||||
|     def by_label(issuables) |     def by_label(issuables) | ||||||
|       return issuables unless label_names_from_params.present? |       return issuables unless label_names_from_params.present? | ||||||
|  | @ -195,7 +186,7 @@ module Issuables | ||||||
| 
 | 
 | ||||||
|     def root_namespace |     def root_namespace | ||||||
|       strong_memoize(:root_namespace) do |       strong_memoize(:root_namespace) do | ||||||
|         (@project || @group)&.root_ancestor |         parent&.root_ancestor | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -4,9 +4,7 @@ module Issues | ||||||
|   class ConfidentialityFilter < Issuables::BaseFilter |   class ConfidentialityFilter < Issuables::BaseFilter | ||||||
|     CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::PLANNER |     CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::PLANNER | ||||||
| 
 | 
 | ||||||
|     def initialize(current_user:, parent:, assignee_filter:, related_groups: nil, **kwargs) |     def initialize(assignee_filter:, related_groups: nil, **kwargs) | ||||||
|       @current_user = current_user |  | ||||||
|       @parent = parent |  | ||||||
|       @assignee_filter = assignee_filter |       @assignee_filter = assignee_filter | ||||||
|       @related_groups = related_groups |       @related_groups = related_groups | ||||||
| 
 | 
 | ||||||
|  | @ -17,14 +15,14 @@ module Issues | ||||||
|       issues = issues.confidential_only if params[:confidential] |       issues = issues.confidential_only if params[:confidential] | ||||||
| 
 | 
 | ||||||
|       # We do not need to do the confidentiality check if we know that only public issues will be returned |       # We do not need to do the confidentiality check if we know that only public issues will be returned | ||||||
|       return issues.public_only if @current_user.blank? || params[:confidential] == false |       return issues.public_only if current_user.blank? || params[:confidential] == false | ||||||
| 
 | 
 | ||||||
|       return issues if user_can_see_all_confidential_issues? |       return issues if user_can_see_all_confidential_issues? | ||||||
| 
 | 
 | ||||||
|       issues.public_only.or( |       issues.public_only.or( | ||||||
|         issues.confidential_only.merge( |         issues.confidential_only.merge( | ||||||
|           issues.authored(@current_user) |           issues.authored(current_user) | ||||||
|             .or(issues.assigned_to(@current_user)) |             .or(issues.assigned_to(current_user)) | ||||||
|             .or(access_to_parent_exists(issues)) |             .or(access_to_parent_exists(issues)) | ||||||
|         ) |         ) | ||||||
|       ).allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422045') |       ).allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422045') | ||||||
|  | @ -33,18 +31,18 @@ module Issues | ||||||
|     private |     private | ||||||
| 
 | 
 | ||||||
|     def user_can_see_all_confidential_issues? |     def user_can_see_all_confidential_issues? | ||||||
|       Ability.allowed?(@current_user, :read_all_resources) || |       Ability.allowed?(current_user, :read_all_resources) || | ||||||
|         Ability.allowed?(@current_user, :read_confidential_issues, @parent) || |         Ability.allowed?(current_user, :read_confidential_issues, parent) || | ||||||
|         # If already filtering by assignee we can skip confidentiality checks since a user |         # If already filtering by assignee we can skip confidentiality checks since a user | ||||||
|         # can always see confidential issues assigned to them. This is just an |         # can always see confidential issues assigned to them. This is just an | ||||||
|         # optimization since a very common use case of this Finder is to load the |         # optimization since a very common use case of this Finder is to load the | ||||||
|         # count of issues assigned to the user for the header bar. |         # count of issues assigned to the user for the header bar. | ||||||
|         @assignee_filter.includes_user?(@current_user) |         @assignee_filter.includes_user?(current_user) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     def access_to_parent_exists(issues) |     def access_to_parent_exists(issues) | ||||||
|       access_to_project_level_issue_exists = issues.where_exists( |       access_to_project_level_issue_exists = issues.where_exists( | ||||||
|         @current_user.authorizations_for_projects( |         current_user.authorizations_for_projects( | ||||||
|           min_access_level: CONFIDENTIAL_ACCESS_LEVEL, |           min_access_level: CONFIDENTIAL_ACCESS_LEVEL, | ||||||
|           related_project_column: 'issues.project_id' |           related_project_column: 'issues.project_id' | ||||||
|         ) |         ) | ||||||
|  | @ -55,7 +53,7 @@ module Issues | ||||||
|       access_to_project_level_issue_exists.project_level.or( |       access_to_project_level_issue_exists.project_level.or( | ||||||
|         issues.group_level.in_namespaces( |         issues.group_level.in_namespaces( | ||||||
|           Group.id_in( |           Group.id_in( | ||||||
|             Group.groups_user_can(@related_groups, @current_user, :read_confidential_issues, same_root: true) |             Group.groups_user_can(@related_groups, current_user, :read_confidential_issues, same_root: true) | ||||||
|           ) |           ) | ||||||
|         ) |         ) | ||||||
|       ) |       ) | ||||||
|  |  | ||||||
|  | @ -129,6 +129,7 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { | ||||||
|                     tooltip |                     tooltip | ||||||
|                     hasDetails |                     hasDetails | ||||||
|                     detailsPath |                     detailsPath | ||||||
|  |                     deploymentDetailsPath | ||||||
|                     group |                     group | ||||||
|                     label |                     label | ||||||
|                     text |                     text | ||||||
|  |  | ||||||
|  | @ -11,6 +11,8 @@ module Types | ||||||
|         null: true, |         null: true, | ||||||
|         calls_gitaly: true, |         calls_gitaly: true, | ||||||
|         description: 'Action information for the status. This includes method, button title, icon, path, and title.' |         description: 'Action information for the status. This includes method, button title, icon, path, and title.' | ||||||
|  |       field :deployment_details_path, GraphQL::Types::String, null: true, | ||||||
|  |         description: 'Path of the deployment details for the status.' | ||||||
|       field :details_path, GraphQL::Types::String, null: true, |       field :details_path, GraphQL::Types::String, null: true, | ||||||
|         description: 'Path of the details for the status.' |         description: 'Path of the details for the status.' | ||||||
|       field :favicon, GraphQL::Types::String, null: true, |       field :favicon, GraphQL::Types::String, null: true, | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| module AlertManagement | module AlertManagement | ||||||
|   class MetricImage < ApplicationRecord |   class MetricImage < ApplicationRecord | ||||||
|     include MetricImageUploading |     include MetricImageUploading | ||||||
|  | 
 | ||||||
|     self.table_name = 'alert_management_alert_metric_images' |     self.table_name = 'alert_management_alert_metric_images' | ||||||
| 
 | 
 | ||||||
|     belongs_to :alert, class_name: 'AlertManagement::Alert', foreign_key: 'alert_id', inverse_of: :metric_images |     belongs_to :alert, class_name: 'AlertManagement::Alert', foreign_key: 'alert_id', inverse_of: :metric_images | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class ProtectedBranch::MergeAccessLevel < ApplicationRecord | class ProtectedBranch::MergeAccessLevel < ApplicationRecord | ||||||
|   include ProtectedBranchAccess |   include ProtectedBranchAccess | ||||||
|  | 
 | ||||||
|   # default value for the access_level column |   # default value for the access_level column | ||||||
|   GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER |   GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| class ProtectedBranch::PushAccessLevel < ApplicationRecord | class ProtectedBranch::PushAccessLevel < ApplicationRecord | ||||||
|   include ProtectedBranchAccess |   include ProtectedBranchAccess | ||||||
|   include ProtectedRefDeployKeyAccess |   include ProtectedRefDeployKeyAccess | ||||||
|  | 
 | ||||||
|   # default value for the access_level column |   # default value for the access_level column | ||||||
|   GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER |   GITLAB_DEFAULT_ACCESS_LEVEL = Gitlab::Access::MAINTAINER | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -147,16 +147,8 @@ module Boards | ||||||
|     # rubocop: enable CodeReuse/ActiveRecord |     # rubocop: enable CodeReuse/ActiveRecord | ||||||
| 
 | 
 | ||||||
|     def labels_filter |     def labels_filter | ||||||
|       Issuables::LabelFilter.new(params: {}, project: project, group: group) |       Issuables::LabelFilter.new(params: {}, parent: parent) | ||||||
|     end |     end | ||||||
|     strong_memoize_attr :labels_filter |     strong_memoize_attr :labels_filter | ||||||
| 
 |  | ||||||
|     def group |  | ||||||
|       parent if parent.is_a?(Group) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     def project |  | ||||||
|       parent if parent.is_a?(Project) |  | ||||||
|     end |  | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -95,6 +95,8 @@ | ||||||
|   - 2 |   - 2 | ||||||
| - - authorized_projects | - - authorized_projects | ||||||
|   - 2 |   - 2 | ||||||
|  | - - authz_ldap_admin_role | ||||||
|  |   - 1 | ||||||
| - - auto_devops | - - auto_devops | ||||||
|   - 2 |   - 2 | ||||||
| - - auto_merge | - - auto_merge | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class AddDuoFeaturesEnabledCascadingSetting < Gitlab::Database::Migration[2.2] | class AddDuoFeaturesEnabledCascadingSetting < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings |   include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings | ||||||
|  | 
 | ||||||
|   enable_lock_retries! |   enable_lock_retries! | ||||||
| 
 | 
 | ||||||
|   milestone '16.10' |   milestone '16.10' | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapVulnerabilityFeedbackPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | class SwapVulnerabilityFeedbackPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::Swapping |   include Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.0' |   milestone '17.0' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapPackagesBuildInfosPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | class SwapPackagesBuildInfosPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::Swapping |   include Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.0' |   milestone '17.0' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapMergeTrainsPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | class SwapMergeTrainsPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::Swapping |   include Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.0' |   milestone '17.0' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapMergeRequestMetricsPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | class SwapMergeRequestMetricsPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::Swapping |   include Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.0' |   milestone '17.0' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapColumnsForPCiBuildsTriggerRequestAndErasedBy < Gitlab::Database::Migration[2.2] | class SwapColumnsForPCiBuildsTriggerRequestAndErasedBy < Gitlab::Database::Migration[2.2] | ||||||
|   include ::Gitlab::Database::MigrationHelpers::Swapping |   include ::Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.1' |   milestone '17.1' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| class SwapVulnerabilityOccurrencePipelinesPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | class SwapVulnerabilityOccurrencePipelinesPipelineIdConvertToBigint < Gitlab::Database::Migration[2.2] | ||||||
|   include Gitlab::Database::MigrationHelpers::Swapping |   include Gitlab::Database::MigrationHelpers::Swapping | ||||||
|  | 
 | ||||||
|   milestone '17.1' |   milestone '17.1' | ||||||
|   disable_ddl_transaction! |   disable_ddl_transaction! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1948,6 +1948,29 @@ Input type: `AddProjectToSecurityDashboardInput` | ||||||
| | <a id="mutationaddprojecttosecuritydashboarderrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | | <a id="mutationaddprojecttosecuritydashboarderrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | ||||||
| | <a id="mutationaddprojecttosecuritydashboardproject"></a>`project` | [`Project`](#project) | Project that was added to the Instance Security Dashboard. | | | <a id="mutationaddprojecttosecuritydashboardproject"></a>`project` | [`Project`](#project) | Project that was added to the Instance Security Dashboard. | | ||||||
| 
 | 
 | ||||||
|  | ### `Mutation.adminRolesLdapSync` | ||||||
|  | 
 | ||||||
|  | {{< details >}} | ||||||
|  | **Introduced** in GitLab 18.0. | ||||||
|  | **Status**: Experiment. | ||||||
|  | {{< /details >}} | ||||||
|  | 
 | ||||||
|  | Input type: `AdminRolesLdapSyncInput` | ||||||
|  | 
 | ||||||
|  | #### Arguments | ||||||
|  | 
 | ||||||
|  | | Name | Type | Description | | ||||||
|  | | ---- | ---- | ----------- | | ||||||
|  | | <a id="mutationadminrolesldapsyncclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | ||||||
|  | 
 | ||||||
|  | #### Fields | ||||||
|  | 
 | ||||||
|  | | Name | Type | Description | | ||||||
|  | | ---- | ---- | ----------- | | ||||||
|  | | <a id="mutationadminrolesldapsyncclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | | ||||||
|  | | <a id="mutationadminrolesldapsyncerrors"></a>`errors` | [`[String!]`](#string) | Errors encountered during operation. | | ||||||
|  | | <a id="mutationadminrolesldapsyncsuccess"></a>`success` | [`Boolean`](#boolean) | Whether the sync was successfully enqueued. | | ||||||
|  | 
 | ||||||
| ### `Mutation.adminSidekiqQueuesDeleteJobs` | ### `Mutation.adminSidekiqQueuesDeleteJobs` | ||||||
| 
 | 
 | ||||||
| Input type: `AdminSidekiqQueuesDeleteJobsInput` | Input type: `AdminSidekiqQueuesDeleteJobsInput` | ||||||
|  | @ -25892,6 +25915,7 @@ Details of the import status of a project. | ||||||
| | Name | Type | Description | | | Name | Type | Description | | ||||||
| | ---- | ---- | ----------- | | | ---- | ---- | ----------- | | ||||||
| | <a id="detailedstatusaction"></a>`action` | [`StatusAction`](#statusaction) | Action information for the status. This includes method, button title, icon, path, and title. | | | <a id="detailedstatusaction"></a>`action` | [`StatusAction`](#statusaction) | Action information for the status. This includes method, button title, icon, path, and title. | | ||||||
|  | | <a id="detailedstatusdeploymentdetailspath"></a>`deploymentDetailsPath` | [`String`](#string) | Path of the deployment details for the status. | | ||||||
| | <a id="detailedstatusdetailspath"></a>`detailsPath` | [`String`](#string) | Path of the details for the status. | | | <a id="detailedstatusdetailspath"></a>`detailsPath` | [`String`](#string) | Path of the details for the status. | | ||||||
| | <a id="detailedstatusfavicon"></a>`favicon` | [`String`](#string) | Favicon of the status. | | | <a id="detailedstatusfavicon"></a>`favicon` | [`String`](#string) | Favicon of the status. | | ||||||
| | <a id="detailedstatusgroup"></a>`group` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 16.4. The `group` attribute is deprecated. Use `name` instead. | | | <a id="detailedstatusgroup"></a>`group` {{< icon name="warning-solid" >}} | [`String`](#string) | **Deprecated** in GitLab 16.4. The `group` attribute is deprecated. Use `name` instead. | | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ Test the regex patterns carefully. Tool output formats can change over time, and | ||||||
| 
 | 
 | ||||||
| | Tool       | Language | Command        | Regex pattern | | | Tool       | Language | Command        | Regex pattern | | ||||||
| |------------|----------|----------------|---------------| | |------------|----------|----------------|---------------| | ||||||
| | pytest-cov | Python   | `pytest --cov` | `/TOTAL.*? (100(?:\.0+)?\%\|[1-9]?\d(?:\.\d+)?\%)$/` | | | pytest-cov | Python   | `pytest --cov` | `/TOTAL.*? (100(?:\.0+)?\%\\|[1-9]?\d(?:\.\d+)?\%)$/` | | ||||||
| | Simplecov  | Ruby     | `rspec spec`   | `/\(\d+.\d+\%\) covered/` | | | Simplecov  | Ruby     | `rspec spec`   | `/\(\d+.\d+\%\) covered/` | | ||||||
| 
 | 
 | ||||||
| {{< /tab >}} | {{< /tab >}} | ||||||
|  | @ -84,7 +84,7 @@ Test the regex patterns carefully. Tool output formats can change over time, and | ||||||
| | Tool      | Language    | Command                            | Regex pattern | | | Tool      | Language    | Command                            | Regex pattern | | ||||||
| |-----------|-------------|------------------------------------|---------------| | |-----------|-------------|------------------------------------|---------------| | ||||||
| | JaCoCo    | Java/Kotlin | `./gradlew test jacocoTestReport`  | `/Total.*?([0-9]{1,3})%/` | | | JaCoCo    | Java/Kotlin | `./gradlew test jacocoTestReport`  | `/Total.*?([0-9]{1,3})%/` | | ||||||
| | Scoverage | Scala       | `sbt coverage test coverageReport` | `/(?i)total.*? (100(?:\.0+)?\%\|[1-9]?\d(?:\.\d+)?\%)$/` | | | Scoverage | Scala       | `sbt coverage test coverageReport` | `/(?i)total.*? (100(?:\.0+)?\%\\|[1-9]?\d(?:\.\d+)?\%)$/` | | ||||||
| 
 | 
 | ||||||
| {{< /tab >}} | {{< /tab >}} | ||||||
| 
 | 
 | ||||||
|  | @ -131,7 +131,7 @@ Test the regex patterns carefully. Tool output formats can change over time, and | ||||||
| | Tool        | Command            | Regex pattern | | | Tool        | Command            | Regex pattern | | ||||||
| |-------------|--------------------|---------------| | |-------------|--------------------|---------------| | ||||||
| | excoveralls | None               | `/\[TOTAL\]\s+(\d+\.\d+)%/` | | | excoveralls | None               | `/\[TOTAL\]\s+(\d+\.\d+)%/` | | ||||||
| | mix         | `mix test --cover` | `/\d+.\d+\%\s+\|\s+Total/` | | | mix         | `mix test --cover` | `/\d+.\d+\%\s+\\|\s+Total/` | | ||||||
| 
 | 
 | ||||||
| {{< /tab >}} | {{< /tab >}} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -70,8 +70,7 @@ module Gitlab | ||||||
|             LabelFilter.new( |             LabelFilter.new( | ||||||
|               stage: stage, |               stage: stage, | ||||||
|               params: params, |               params: params, | ||||||
|               project: nil, |               parent: root_ancestor | ||||||
|               group: root_ancestor |  | ||||||
|             ).filter(query) |             ).filter(query) | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,10 +8,10 @@ module Gitlab | ||||||
|         class LabelFilter < Issuables::LabelFilter |         class LabelFilter < Issuables::LabelFilter | ||||||
|           extend ::Gitlab::Utils::Override |           extend ::Gitlab::Utils::Override | ||||||
| 
 | 
 | ||||||
|           def initialize(stage:, project:, group:, **kwargs) |           def initialize(stage:, **kwargs) | ||||||
|             @stage = stage |             @stage = stage | ||||||
| 
 | 
 | ||||||
|             super(project: project, group: group, **kwargs) |             super(**kwargs) | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           private |           private | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ module Gitlab | ||||||
|       # Migration only version of MergeRequest table |       # Migration only version of MergeRequest table | ||||||
|       class MergeRequest < ::ApplicationRecord |       class MergeRequest < ::ApplicationRecord | ||||||
|         include EachBatch |         include EachBatch | ||||||
|  | 
 | ||||||
|         validates :suggested_reviewers, json_schema: { filename: 'merge_request_suggested_reviewers' } |         validates :suggested_reviewers, json_schema: { filename: 'merge_request_suggested_reviewers' } | ||||||
| 
 | 
 | ||||||
|         CORRECTED_REGEXP_STR = "^(\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP)" |         CORRECTED_REGEXP_STR = "^(\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP)" | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ module Gitlab | ||||||
|         self.inheritance_column = :_type_disabled |         self.inheritance_column = :_type_disabled | ||||||
| 
 | 
 | ||||||
|         include ::Integrations::BaseDataFields |         include ::Integrations::BaseDataFields | ||||||
|  | 
 | ||||||
|         attr_encrypted :url, encryption_options |         attr_encrypted :url, encryption_options | ||||||
|         attr_encrypted :api_url, encryption_options |         attr_encrypted :api_url, encryption_options | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -91,6 +91,10 @@ module Gitlab | ||||||
|         def confirmation_message |         def confirmation_message | ||||||
|           nil |           nil | ||||||
|         end |         end | ||||||
|  | 
 | ||||||
|  |         def deployment_details_path | ||||||
|  |           nil | ||||||
|  |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ require 'spec_helper' | ||||||
| RSpec.describe Issuables::CrmContactFilter do | RSpec.describe Issuables::CrmContactFilter do | ||||||
|   let_it_be(:group) { create(:group) } |   let_it_be(:group) { create(:group) } | ||||||
|   let_it_be(:project) { create(:project, group: group) } |   let_it_be(:project) { create(:project, group: group) } | ||||||
|  |   let_it_be(:developer) { create(:user, developer_of: group) } | ||||||
| 
 | 
 | ||||||
|   let_it_be(:contact1) { create(:contact, group: group) } |   let_it_be(:contact1) { create(:contact, group: group) } | ||||||
|   let_it_be(:contact2) { create(:contact, group: group) } |   let_it_be(:contact2) { create(:contact, group: group) } | ||||||
|  | @ -14,32 +15,36 @@ RSpec.describe Issuables::CrmContactFilter do | ||||||
|   let_it_be(:contact2_issue1) { create(:issue, project: project) } |   let_it_be(:contact2_issue1) { create(:issue, project: project) } | ||||||
|   let_it_be(:issues) { Issue.where(id: [contact1_issue1.id, contact1_issue2.id, contact2_issue1.id]) } |   let_it_be(:issues) { Issue.where(id: [contact1_issue1.id, contact1_issue2.id, contact2_issue1.id]) } | ||||||
| 
 | 
 | ||||||
|  |   let(:params) { {} } | ||||||
|  | 
 | ||||||
|   before_all do |   before_all do | ||||||
|     create(:issue_customer_relations_contact, issue: contact1_issue1, contact: contact1) |     create(:issue_customer_relations_contact, issue: contact1_issue1, contact: contact1) | ||||||
|     create(:issue_customer_relations_contact, issue: contact1_issue2, contact: contact1) |     create(:issue_customer_relations_contact, issue: contact1_issue2, contact: contact1) | ||||||
|     create(:issue_customer_relations_contact, issue: contact2_issue1, contact: contact2) |     create(:issue_customer_relations_contact, issue: contact2_issue1, contact: contact2) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   subject(:crm_contact_filter) { described_class.new(params: params, parent: group, current_user: developer) } | ||||||
|  | 
 | ||||||
|   describe 'when a contact has issues' do |   describe 'when a contact has issues' do | ||||||
|     it 'returns all contact1 issues' do |     it 'returns all contact1 issues' do | ||||||
|       params = { crm_contact_id: contact1.id } |       params[:crm_contact_id] = contact1.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact1_issue1, contact1_issue2) |       expect(crm_contact_filter.filter(issues)).to contain_exactly(contact1_issue1, contact1_issue2) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns all contact2 issues' do |     it 'returns all contact2 issues' do | ||||||
|       params = { crm_contact_id: contact2.id } |       params[:crm_contact_id] = contact2.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact2_issue1) |       expect(crm_contact_filter.filter(issues)).to contain_exactly(contact2_issue1) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'when a contact has no issues' do |   describe 'when a contact has no issues' do | ||||||
|     it 'returns no issues' do |     it 'returns no issues' do | ||||||
|       contact3 = create(:contact, group: group) |       contact3 = create(:contact, group: group) | ||||||
|       params = { crm_contact_id: contact3.id } |       params[:crm_contact_id] = contact3.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to be_empty |       expect(crm_contact_filter.filter(issues)).to be_empty | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ require 'spec_helper' | ||||||
| RSpec.describe Issuables::CrmOrganizationFilter do | RSpec.describe Issuables::CrmOrganizationFilter do | ||||||
|   let_it_be(:group) { create(:group) } |   let_it_be(:group) { create(:group) } | ||||||
|   let_it_be(:project) { create(:project, group: group) } |   let_it_be(:project) { create(:project, group: group) } | ||||||
|  |   let_it_be(:developer) { create(:user, developer_of: group) } | ||||||
| 
 | 
 | ||||||
|   let_it_be(:crm_organization1) { create(:crm_organization, group: group) } |   let_it_be(:crm_organization1) { create(:crm_organization, group: group) } | ||||||
|   let_it_be(:crm_organization2) { create(:crm_organization, group: group) } |   let_it_be(:crm_organization2) { create(:crm_organization, group: group) } | ||||||
|  | @ -17,32 +18,36 @@ RSpec.describe Issuables::CrmOrganizationFilter do | ||||||
|   let_it_be(:contact3_issue) { create(:issue, project: project) } |   let_it_be(:contact3_issue) { create(:issue, project: project) } | ||||||
|   let_it_be(:issues) { Issue.where(id: [contact1_issue.id, contact2_issue.id, contact3_issue.id]) } |   let_it_be(:issues) { Issue.where(id: [contact1_issue.id, contact2_issue.id, contact3_issue.id]) } | ||||||
| 
 | 
 | ||||||
|  |   let(:params) { {} } | ||||||
|  | 
 | ||||||
|   before_all do |   before_all do | ||||||
|     create(:issue_customer_relations_contact, issue: contact1_issue, contact: contact1) |     create(:issue_customer_relations_contact, issue: contact1_issue, contact: contact1) | ||||||
|     create(:issue_customer_relations_contact, issue: contact2_issue, contact: contact2) |     create(:issue_customer_relations_contact, issue: contact2_issue, contact: contact2) | ||||||
|     create(:issue_customer_relations_contact, issue: contact3_issue, contact: contact3) |     create(:issue_customer_relations_contact, issue: contact3_issue, contact: contact3) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   subject(:crm_organization_filter) { described_class.new(params: params, parent: group, current_user: developer) } | ||||||
|  | 
 | ||||||
|   describe 'when an organization has issues' do |   describe 'when an organization has issues' do | ||||||
|     it 'returns all crm_organization1 issues' do |     it 'returns all crm_organization1 issues' do | ||||||
|       params = { crm_organization_id: crm_organization1.id } |       params[:crm_organization_id] = crm_organization1.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact1_issue, contact2_issue) |       expect(crm_organization_filter.filter(issues)).to contain_exactly(contact1_issue, contact2_issue) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns all crm_organization2 issues' do |     it 'returns all crm_organization2 issues' do | ||||||
|       params = { crm_organization_id: crm_organization2.id } |       params[:crm_organization_id] = crm_organization2.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to contain_exactly(contact3_issue) |       expect(crm_organization_filter.filter(issues)).to contain_exactly(contact3_issue) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe 'when an organization has no issues' do |   describe 'when an organization has no issues' do | ||||||
|     it 'returns no issues' do |     it 'returns no issues' do | ||||||
|       crm_organization3 = create(:crm_organization, group: group) |       crm_organization3 = create(:crm_organization, group: group) | ||||||
|       params = { crm_organization_id: crm_organization3.id } |       params[:crm_organization_id] = crm_organization3.id | ||||||
| 
 | 
 | ||||||
|       expect(described_class.new(params: params).filter(issues)).to be_empty |       expect(crm_organization_filter.filter(issues)).to be_empty | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_help | ||||||
| import { stubComponent } from 'helpers/stub_component'; | import { stubComponent } from 'helpers/stub_component'; | ||||||
| import { | import { | ||||||
|   delayedJob, |   delayedJob, | ||||||
|  |   bridgeJob, | ||||||
|   mockJob, |   mockJob, | ||||||
|   mockJobWithoutDetails, |   mockJobWithoutDetails, | ||||||
|   mockJobWithUnauthorizedAction, |   mockJobWithUnauthorizedAction, | ||||||
|  | @ -84,6 +85,12 @@ describe('pipeline graph job item', () => { | ||||||
| 
 | 
 | ||||||
|       expect(wrapper.text()).toBe(mockJob.name); |       expect(wrapper.text()).toBe(mockJob.name); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     it('should use deployment details path as the details path for manual bridge jobs', () => { | ||||||
|  |       createWrapper({ props: { job: bridgeJob } }); | ||||||
|  | 
 | ||||||
|  |       expect(findJobItemContent().attributes('href')).toBe(bridgeJob.status.deploymentDetailsPath); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('name without link', () => { |   describe('name without link', () => { | ||||||
|  |  | ||||||
|  | @ -222,6 +222,7 @@ export const wrappedPipelineReturn = { | ||||||
|                             label: 'passed', |                             label: 'passed', | ||||||
|                             hasDetails: true, |                             hasDetails: true, | ||||||
|                             detailsPath: '/root/elemenohpee/-/jobs/1662', |                             detailsPath: '/root/elemenohpee/-/jobs/1662', | ||||||
|  |                             deploymentDetailsPath: null, | ||||||
|                             group: 'success', |                             group: 'success', | ||||||
|                             action: { |                             action: { | ||||||
|                               __typename: 'StatusAction', |                               __typename: 'StatusAction', | ||||||
|  | @ -300,6 +301,26 @@ export const delayedJob = { | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | export const bridgeJob = { | ||||||
|  |   id: 4255, | ||||||
|  |   name: 'test', | ||||||
|  |   kind: BRIDGE_KIND, | ||||||
|  |   status: { | ||||||
|  |     icon: 'status_manual', | ||||||
|  |     text: 'Manual', | ||||||
|  |     label: 'manual action', | ||||||
|  |     tooltip: 'View deployment details page', | ||||||
|  |     group: 'manual', | ||||||
|  |     deploymentDetailsPath: 'path/to/deployment', | ||||||
|  |     hasDetails: false, | ||||||
|  |     action: { | ||||||
|  |       icon: null, | ||||||
|  |       title: null, | ||||||
|  |       path: null, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| export const mockJob = { | export const mockJob = { | ||||||
|   id: 4256, |   id: 4256, | ||||||
|   name: 'test', |   name: 'test', | ||||||
|  |  | ||||||
|  | @ -1215,6 +1215,7 @@ export const mockPipelineStatusUpdatedResponse = { | ||||||
|       __typename: 'Pipeline', |       __typename: 'Pipeline', | ||||||
|       detailedStatus: { |       detailedStatus: { | ||||||
|         detailsPath: '/root/simple-ci-project/-/pipelines/1257', |         detailsPath: '/root/simple-ci-project/-/pipelines/1257', | ||||||
|  |         deploymentDetailsPath: null, | ||||||
|         icon: 'status_success', |         icon: 'status_success', | ||||||
|         id: 'success-1255-1255', |         id: 'success-1255-1255', | ||||||
|         label: 'passed', |         label: 'passed', | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ RSpec.describe Types::Ci::DetailedStatusType do | ||||||
|       :id, :group, :icon, :favicon, |       :id, :group, :icon, :favicon, | ||||||
|       :details_path, :has_details, |       :details_path, :has_details, | ||||||
|       :label, :name, :text, :tooltip, |       :label, :name, :text, :tooltip, | ||||||
|       :action |       :action, :deployment_details_path | ||||||
|     ) |     ) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,4 +20,10 @@ RSpec.describe Gitlab::Ci::Status::Core do | ||||||
|       expect(status.confirmation_message).to be_nil |       expect(status.confirmation_message).to be_nil | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   describe '#deployment_details_path' do | ||||||
|  |     it 'returns nil by default' do | ||||||
|  |       expect(status.deployment_details_path).to be_nil | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -18,20 +18,20 @@ RSpec.describe 'cross-database foreign keys' do | ||||||
|       'system_access_microsoft_applications.namespace_id', |       'system_access_microsoft_applications.namespace_id', | ||||||
|       'ci_runner_taggings.tag_id',                               # https://gitlab.com/gitlab-org/gitlab/-/issues/467664 |       'ci_runner_taggings.tag_id',                               # https://gitlab.com/gitlab-org/gitlab/-/issues/467664 | ||||||
|       'ci_runner_taggings_instance_type.tag_id',                 # https://gitlab.com/gitlab-org/gitlab/-/issues/467664 |       'ci_runner_taggings_instance_type.tag_id',                 # https://gitlab.com/gitlab-org/gitlab/-/issues/467664 | ||||||
|       'ci_secure_file_states.ci_secure_file_id', |       'ci_secure_file_states.ci_secure_file_id',                         # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'dependency_proxy_blob_states.dependency_proxy_blob_id', |       'dependency_proxy_blob_states.dependency_proxy_blob_id',           # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'dependency_proxy_blob_states.group_id', |       'dependency_proxy_blob_states.group_id',                           # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'dependency_proxy_manifest_states.dependency_proxy_manifest_id', |       'dependency_proxy_manifest_states.dependency_proxy_manifest_id',   # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'dependency_proxy_manifest_states.group_id', |       'dependency_proxy_manifest_states.group_id',                       # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'lfs_objects_projects.lfs_object_id', |       'lfs_objects_projects.lfs_object_id',                              # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'merge_request_diff_details.merge_request_diff_id', |       'merge_request_diff_details.merge_request_diff_id',                # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'merge_request_diff_details.project_id', |       'merge_request_diff_details.project_id',                           # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'pages_deployment_states.pages_deployment_id', |       'pages_deployment_states.pages_deployment_id',                     # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'pages_deployment_states.project_id', |       'pages_deployment_states.project_id',                              # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'snippet_repositories.snippet_id', |       'snippet_repositories.snippet_id',                                 # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'snippet_repositories.snippet_organization_id', |       'snippet_repositories.snippet_organization_id',                    # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'snippet_repositories.snippet_project_id', |       'snippet_repositories.snippet_project_id',                         # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'upload_states.upload_id', |       'upload_states.upload_id',                                         # https://gitlab.com/groups/gitlab-org/-/epics/17347 | ||||||
|       'application_settings.web_ide_oauth_application_id',          # https://gitlab.com/gitlab-org/gitlab/-/issues/531355 |       'application_settings.web_ide_oauth_application_id',          # https://gitlab.com/gitlab-org/gitlab/-/issues/531355 | ||||||
|       'ai_settings.amazon_q_oauth_application_id',                  # https://gitlab.com/gitlab-org/gitlab/-/issues/531356 |       'ai_settings.amazon_q_oauth_application_id',                  # https://gitlab.com/gitlab-org/gitlab/-/issues/531356 | ||||||
|       'ai_settings.duo_workflow_oauth_application_id',              # https://gitlab.com/gitlab-org/gitlab/-/issues/531356 |       'ai_settings.duo_workflow_oauth_application_id',              # https://gitlab.com/gitlab-org/gitlab/-/issues/531356 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue