diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-09 00:13:09 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-09 00:13:09 +0300 |
commit | f26a600a69b3a13d3102d801f5d92d3235ea56d4 (patch) | |
tree | 87393fc4a3de2ff1324ea014563de27512316227 /app/models | |
parent | 03a8aa2ca6a7d7aced2fde7815c8ef85d681db60 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/ci/pipeline.rb | 32 | ||||
-rw-r--r-- | app/models/ci/runner.rb | 8 | ||||
-rw-r--r-- | app/models/concerns/integrations/has_web_hook.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/sortable.rb | 27 | ||||
-rw-r--r-- | app/models/environment.rb | 2 | ||||
-rw-r--r-- | app/models/environment_status.rb | 2 | ||||
-rw-r--r-- | app/models/integrations/buildkite.rb | 8 | ||||
-rw-r--r-- | app/models/issue.rb | 26 | ||||
-rw-r--r-- | app/models/member.rb | 87 | ||||
-rw-r--r-- | app/models/merge_request.rb | 2 | ||||
-rw-r--r-- | app/models/namespace.rb | 2 | ||||
-rw-r--r-- | app/models/onboarding/progress.rb | 118 | ||||
-rw-r--r-- | app/models/onboarding_progress.rb | 114 | ||||
-rw-r--r-- | app/models/project.rb | 4 |
14 files changed, 247 insertions, 186 deletions
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index f2d4c9a43c3..4c0fbcfe330 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -611,7 +611,7 @@ module Ci if cascade_to_children # cancel any bridges that could spin up new child pipelines - cancel_jobs(bridges_in_self_and_descendants.cancelable, retries: retries, auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id) + cancel_jobs(bridges_in_self_and_project_descendants.cancelable, retries: retries, auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id) cancel_children(auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id, execute_async: execute_async) end end @@ -943,26 +943,26 @@ module Ci ).base_and_descendants.select(:id) end - def build_with_artifacts_in_self_and_descendants(name) - builds_in_self_and_descendants + def build_with_artifacts_in_self_and_project_descendants(name) + builds_in_self_and_project_descendants .ordered_by_pipeline # find job in hierarchical order .with_downloadable_artifacts .find_by_name(name) end - def builds_in_self_and_descendants - Ci::Build.latest.where(pipeline: self_and_descendants) + def builds_in_self_and_project_descendants + Ci::Build.latest.where(pipeline: self_and_project_descendants) end - def bridges_in_self_and_descendants - Ci::Bridge.latest.where(pipeline: self_and_descendants) + def bridges_in_self_and_project_descendants + Ci::Bridge.latest.where(pipeline: self_and_project_descendants) end - def environments_in_self_and_descendants(deployment_status: nil) + def environments_in_self_and_project_descendants(deployment_status: nil) # We limit to 100 unique environments for application safety. # See: https://gitlab.com/gitlab-org/gitlab/-/issues/340781#note_699114700 expanded_environment_names = - builds_in_self_and_descendants.joins(:metadata) + builds_in_self_and_project_descendants.joins(:metadata) .where.not('ci_builds_metadata.expanded_environment_name' => nil) .distinct('ci_builds_metadata.expanded_environment_name') .limit(100) @@ -977,17 +977,17 @@ module Ci end # With multi-project and parent-child pipelines - def all_pipelines_in_hierarchy + def upstream_and_all_downstreams object_hierarchy.all_objects end # With only parent-child pipelines - def self_and_ancestors + def self_and_project_ancestors object_hierarchy(project_condition: :same).base_and_ancestors end # With only parent-child pipelines - def self_and_descendants + def self_and_project_descendants object_hierarchy(project_condition: :same).base_and_descendants end @@ -996,8 +996,8 @@ module Ci object_hierarchy(project_condition: :same).descendants end - def self_and_descendants_complete? - self_and_descendants.all?(&:complete?) + def self_and_project_descendants_complete? + self_and_project_descendants.all?(&:complete?) end # Follow the parent-child relationships and return the top-level parent @@ -1061,8 +1061,8 @@ module Ci latest_report_builds(Ci::JobArtifact.of_report_type(:test)).preload(:project, :metadata) end - def latest_report_builds_in_self_and_descendants(reports_scope = ::Ci::JobArtifact.all_reports) - builds_in_self_and_descendants.with_artifacts(reports_scope) + def latest_report_builds_in_self_and_project_descendants(reports_scope = ::Ci::JobArtifact.all_reports) + builds_in_self_and_project_descendants.with_artifacts(reports_scope) end def builds_with_coverage diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 6c3754d84d0..3cbc4c50444 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -359,14 +359,6 @@ module Ci runner_projects.limit(2).count(:all) > 1 end - def assigned_to_group? - runner_namespaces.any? - end - - def assigned_to_project? - runner_projects.any? - end - def match_build_if_online?(build) active? && online? && matches_build?(build) end diff --git a/app/models/concerns/integrations/has_web_hook.rb b/app/models/concerns/integrations/has_web_hook.rb index e9fcb0d151d..e6ca6cc7938 100644 --- a/app/models/concerns/integrations/has_web_hook.rb +++ b/app/models/concerns/integrations/has_web_hook.rb @@ -5,6 +5,7 @@ module Integrations extend ActiveSupport::Concern included do + after_save :update_web_hook!, if: :activated? has_one :service_hook, inverse_of: :integration, foreign_key: :service_id end diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index 65fb62a814f..eccb004b503 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -43,6 +43,33 @@ module Sortable } end + def build_keyset_order_on_joined_column(scope:, attribute_name:, column:, direction:, nullable:) + reversed_direction = direction == :asc ? :desc : :asc + + # rubocop: disable GitlabSecurity/PublicSend + order = ::Gitlab::Pagination::Keyset::Order.build( + [ + ::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: attribute_name, + column_expression: column, + order_expression: column.send(direction).send(nullable), + reversed_order_expression: column.send(reversed_direction).send(nullable), + order_direction: direction, + distinct: false, + add_to_projections: true, + nullable: nullable + ), + ::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( + attribute_name: 'id', + order_expression: arel_table['id'].desc + ) + ] + ) + # rubocop: enable GitlabSecurity/PublicSend + + order.apply_cursor_conditions(scope).reorder(order) + end + private def highest_label_priority(target_type_column: nil, target_type: nil, target_column:, project_column:, excluded_labels: []) diff --git a/app/models/environment.rb b/app/models/environment.rb index bc1b2daf3db..4aab4ab8170 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -84,7 +84,7 @@ class Environment < ApplicationRecord # Search environments which have names like the given query. # Do not set a large limit unless you've confirmed that it works on gitlab.com scale. scope :for_name_like, -> (query, limit: 5) do - where(arel_table[:name].matches("#{sanitize_sql_like query}%")).limit(limit) + where('LOWER(environments.name) LIKE LOWER(?) || \'%\'', sanitize_sql_like(query)).limit(limit) end scope :for_project, -> (project) { where(project_id: project) } diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb index 43b2c7899a1..d06d0a99948 100644 --- a/app/models/environment_status.rb +++ b/app/models/environment_status.rb @@ -100,7 +100,7 @@ class EnvironmentStatus def self.build_environments_status(mr, user, pipeline) return [] unless pipeline - pipeline.environments_in_self_and_descendants.includes(:project).available.map do |environment| + pipeline.environments_in_self_and_project_descendants.includes(:project).available.map do |environment| next unless Ability.allowed?(user, :read_environment, environment) EnvironmentStatus.new(pipeline.project, environment, mr, pipeline.sha) diff --git a/app/models/integrations/buildkite.rb b/app/models/integrations/buildkite.rb index c19e06f055e..7a48e71b934 100644 --- a/app/models/integrations/buildkite.rb +++ b/app/models/integrations/buildkite.rb @@ -8,8 +8,6 @@ module Integrations include ReactivelyCached extend Gitlab::Utils::Override - after_save :ensure_ssl_verification - ENDPOINT = "https://buildkite.com" field :project_url, @@ -50,12 +48,6 @@ module Integrations self.properties = properties.except('enable_ssl_verification') # Remove unused key end - def ensure_ssl_verification - return unless service_hook - - update_web_hook! - end - override :hook_url def hook_url "#{buildkite_endpoint('webhook')}/deliver/#{webhook_token}" diff --git a/app/models/issue.rb b/app/models/issue.rb index 1de2075b456..153747c75df 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -254,32 +254,6 @@ class Issue < ApplicationRecord alias_method :with_state, :with_state_id alias_method :with_states, :with_state_ids - def build_keyset_order_on_joined_column(scope:, attribute_name:, column:, direction:, nullable:) - reversed_direction = direction == :asc ? :desc : :asc - - # rubocop: disable GitlabSecurity/PublicSend - order = ::Gitlab::Pagination::Keyset::Order.build( - [ - ::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( - attribute_name: attribute_name, - column_expression: column, - order_expression: column.send(direction).send(nullable), - reversed_order_expression: column.send(reversed_direction).send(nullable), - order_direction: direction, - distinct: false, - add_to_projections: true, - nullable: nullable - ), - ::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new( - attribute_name: 'id', - order_expression: arel_table['id'].desc - ) - ]) - # rubocop: enable GitlabSecurity/PublicSend - - order.apply_cursor_conditions(scope).order(order) - end - override :order_upvotes_desc def order_upvotes_desc reorder(upvotes_count: :desc) diff --git a/app/models/member.rb b/app/models/member.rb index 186fcd8759f..c5351d5447b 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -184,14 +184,85 @@ class Member < ApplicationRecord unscoped.from(distinct_members, :members) end - scope :order_name_asc, -> { left_join_users.reorder(User.arel_table[:name].asc.nulls_last) } - scope :order_name_desc, -> { left_join_users.reorder(User.arel_table[:name].desc.nulls_last) } - scope :order_recent_sign_in, -> { left_join_users.reorder(User.arel_table[:last_sign_in_at].desc.nulls_last) } - scope :order_oldest_sign_in, -> { left_join_users.reorder(User.arel_table[:last_sign_in_at].asc.nulls_last) } - scope :order_recent_last_activity, -> { left_join_users.reorder(User.arel_table[:last_activity_on].desc.nulls_last) } - scope :order_oldest_last_activity, -> { left_join_users.reorder(User.arel_table[:last_activity_on].asc.nulls_first) } - scope :order_recent_created_user, -> { left_join_users.reorder(User.arel_table[:created_at].desc.nulls_last) } - scope :order_oldest_created_user, -> { left_join_users.reorder(User.arel_table[:created_at].asc.nulls_first) } + scope :order_name_asc, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_full_name', + column: User.arel_table[:name], + direction: :asc, + nullable: :nulls_last + ) + end + + scope :order_name_desc, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_full_name', + column: User.arel_table[:name], + direction: :desc, + nullable: :nulls_last + ) + end + + scope :order_oldest_sign_in, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_last_sign_in_at', + column: User.arel_table[:last_sign_in_at], + direction: :asc, + nullable: :nulls_last + ) + end + + scope :order_recent_sign_in, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_last_sign_in_at', + column: User.arel_table[:last_sign_in_at], + direction: :desc, + nullable: :nulls_last + ) + end + + scope :order_oldest_last_activity, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_last_activity_on', + column: User.arel_table[:last_activity_on], + direction: :asc, + nullable: :nulls_first + ) + end + + scope :order_recent_last_activity, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_last_activity_on', + column: User.arel_table[:last_activity_on], + direction: :desc, + nullable: :nulls_last + ) + end + + scope :order_oldest_created_user, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_created_at', + column: User.arel_table[:created_at], + direction: :asc, + nullable: :nulls_first + ) + end + + scope :order_recent_created_user, -> do + build_keyset_order_on_joined_column( + scope: left_join_users, + attribute_name: 'member_user_created_at', + column: User.arel_table[:created_at], + direction: :desc, + nullable: :nulls_last + ) + end scope :on_project_and_ancestors, ->(project) { where(source: [project] + project.ancestors) } diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 18459805883..d155a295481 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1466,7 +1466,7 @@ class MergeRequest < ApplicationRecord end def environments_in_head_pipeline(deployment_status: nil) - actual_head_pipeline&.environments_in_self_and_descendants(deployment_status: deployment_status) || Environment.none + actual_head_pipeline&.environments_in_self_and_project_descendants(deployment_status: deployment_status) || Environment.none end def fetch_ref! diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 4f0639a08a0..17d4c6d27e6 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -61,7 +61,7 @@ class Namespace < ApplicationRecord has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace' has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner' has_many :pending_builds, class_name: 'Ci::PendingBuild' - has_one :onboarding_progress + has_one :onboarding_progress, class_name: 'Onboarding::Progress' # This should _not_ be `inverse_of: :namespace`, because that would also set # `user.namespace` when this user creates a group with themselves as `owner`. diff --git a/app/models/onboarding/progress.rb b/app/models/onboarding/progress.rb new file mode 100644 index 00000000000..ecc78418256 --- /dev/null +++ b/app/models/onboarding/progress.rb @@ -0,0 +1,118 @@ +# frozen_string_literal: true + +module Onboarding + class Progress < ApplicationRecord + self.table_name = 'onboarding_progresses' + + belongs_to :namespace, optional: false + + validate :namespace_is_root_namespace + + ACTIONS = [ + :git_pull, + :git_write, + :merge_request_created, + :pipeline_created, + :user_added, + :trial_started, + :subscription_created, + :required_mr_approvals_enabled, + :code_owners_enabled, + :scoped_label_created, + :security_scan_enabled, + :issue_created, + :issue_auto_closed, + :repository_imported, + :repository_mirrored, + :secure_dependency_scanning_run, + :secure_container_scanning_run, + :secure_dast_run, + :secure_secret_detection_run, + :secure_coverage_fuzzing_run, + :secure_api_fuzzing_run, + :secure_cluster_image_scanning_run, + :license_scanning_run + ].freeze + + scope :incomplete_actions, ->(actions) do + Array.wrap(actions).inject(self) { |scope, action| scope.where(column_name(action) => nil) } + end + + scope :completed_actions, ->(actions) do + Array.wrap(actions).inject(self) { |scope, action| scope.where.not(column_name(action) => nil) } + end + + scope :completed_actions_with_latest_in_range, ->(actions, range) do + actions = Array(actions) + if actions.size == 1 + where(column_name(actions[0]) => range) + else + action_columns = actions.map { |action| arel_table[column_name(action)] } + completed_actions(actions).where(Arel::Nodes::NamedFunction.new('GREATEST', action_columns).between(range)) + end + end + + class << self + def onboard(namespace) + return unless root_namespace?(namespace) + + create(namespace: namespace) + end + + def onboarding?(namespace) + where(namespace: namespace).any? + end + + def register(namespace, actions) + actions = Array(actions) + return unless root_namespace?(namespace) && actions.difference(ACTIONS).empty? + + onboarding_progress = find_by(namespace: namespace) + return unless onboarding_progress + + now = Time.current + nil_actions = actions.select { |action| onboarding_progress[column_name(action)].nil? } + return if nil_actions.empty? + + updates = nil_actions.inject({}) { |sum, action| sum.merge!({ column_name(action) => now }) } + onboarding_progress.update!(updates) + end + + def completed?(namespace, action) + return unless root_namespace?(namespace) && ACTIONS.include?(action) + + action_column = column_name(action) + where(namespace: namespace).where.not(action_column => nil).exists? + end + + def not_completed?(namespace_id, action) + return unless ACTIONS.include?(action) + + action_column = column_name(action) + exists?(namespace_id: namespace_id, action_column => nil) + end + + def column_name(action) + :"#{action}_at" + end + + private + + def root_namespace?(namespace) + namespace&.root? + end + end + + def number_of_completed_actions + attributes.extract!(*ACTIONS.map { |action| self.class.column_name(action).to_s }).compact!.size + end + + private + + def namespace_is_root_namespace + return unless namespace + + errors.add(:namespace, _('must be a root namespace')) if namespace.has_parent? + end + end +end diff --git a/app/models/onboarding_progress.rb b/app/models/onboarding_progress.rb deleted file mode 100644 index e5851c5cfc5..00000000000 --- a/app/models/onboarding_progress.rb +++ /dev/null @@ -1,114 +0,0 @@ -# frozen_string_literal: true - -class OnboardingProgress < ApplicationRecord - belongs_to :namespace, optional: false - - validate :namespace_is_root_namespace - - ACTIONS = [ - :git_pull, - :git_write, - :merge_request_created, - :pipeline_created, - :user_added, - :trial_started, - :subscription_created, - :required_mr_approvals_enabled, - :code_owners_enabled, - :scoped_label_created, - :security_scan_enabled, - :issue_created, - :issue_auto_closed, - :repository_imported, - :repository_mirrored, - :secure_dependency_scanning_run, - :secure_container_scanning_run, - :secure_dast_run, - :secure_secret_detection_run, - :secure_coverage_fuzzing_run, - :secure_api_fuzzing_run, - :secure_cluster_image_scanning_run, - :license_scanning_run - ].freeze - - scope :incomplete_actions, -> (actions) do - Array.wrap(actions).inject(self) { |scope, action| scope.where(column_name(action) => nil) } - end - - scope :completed_actions, -> (actions) do - Array.wrap(actions).inject(self) { |scope, action| scope.where.not(column_name(action) => nil) } - end - - scope :completed_actions_with_latest_in_range, -> (actions, range) do - actions = Array(actions) - if actions.size == 1 - where(column_name(actions[0]) => range) - else - action_columns = actions.map { |action| arel_table[column_name(action)] } - completed_actions(actions).where(Arel::Nodes::NamedFunction.new('GREATEST', action_columns).between(range)) - end - end - - class << self - def onboard(namespace) - return unless root_namespace?(namespace) - - create(namespace: namespace) - end - - def onboarding?(namespace) - where(namespace: namespace).any? - end - - def register(namespace, actions) - actions = Array(actions) - return unless root_namespace?(namespace) && actions.difference(ACTIONS).empty? - - onboarding_progress = find_by(namespace: namespace) - return unless onboarding_progress - - now = Time.current - nil_actions = actions.select { |action| onboarding_progress[column_name(action)].nil? } - return if nil_actions.empty? - - updates = nil_actions.inject({}) { |sum, action| sum.merge!({ column_name(action) => now }) } - onboarding_progress.update!(updates) - end - - def completed?(namespace, action) - return unless root_namespace?(namespace) && ACTIONS.include?(action) - - action_column = column_name(action) - where(namespace: namespace).where.not(action_column => nil).exists? - end - - def not_completed?(namespace_id, action) - return unless ACTIONS.include?(action) - - action_column = column_name(action) - where(namespace_id: namespace_id).where(action_column => nil).exists? - end - - def column_name(action) - :"#{action}_at" - end - - private - - def root_namespace?(namespace) - namespace && namespace.root? - end - end - - def number_of_completed_actions - attributes.extract!(*ACTIONS.map { |action| self.class.column_name(action).to_s }).compact!.size - end - - private - - def namespace_is_root_namespace - return unless namespace - - errors.add(:namespace, _('must be a root namespace')) if namespace.has_parent? - end -end diff --git a/app/models/project.rb b/app/models/project.rb index 78ec17acc01..0be24252fa8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1170,7 +1170,7 @@ class Project < ApplicationRecord latest_pipeline = ci_pipelines.latest_successful_for_ref(ref) return unless latest_pipeline - latest_pipeline.build_with_artifacts_in_self_and_descendants(job_name) + latest_pipeline.build_with_artifacts_in_self_and_project_descendants(job_name) end def latest_successful_build_for_sha(job_name, sha) @@ -1179,7 +1179,7 @@ class Project < ApplicationRecord latest_pipeline = ci_pipelines.latest_successful_for_sha(sha) return unless latest_pipeline - latest_pipeline.build_with_artifacts_in_self_and_descendants(job_name) + latest_pipeline.build_with_artifacts_in_self_and_project_descendants(job_name) end def latest_successful_build_for_ref!(job_name, ref = default_branch) |