diff options
| author | Dennis Tang <dtang@gitlab.com> | 2018-05-11 18:42:20 +0200 | 
|---|---|---|
| committer | Dennis Tang <dtang@gitlab.com> | 2018-05-11 18:42:20 +0200 | 
| commit | 2205ed4f07265a43d2561ab2657557e317e7b9c0 (patch) | |
| tree | 08e8373f874b59e78d97dd87b1c687d3458823d9 /app/models/project.rb | |
| parent | 3a3f4a348be936abde6881fc3909026932bf97ab (diff) | |
| parent | f4e234d92a2ff31dc681d56b52e9fbbbe3f931b1 (diff) | |
| download | gitlab-ce-2205ed4f07265a43d2561ab2657557e317e7b9c0.tar.gz | |
Merge remote-tracking branch 'origin/master' into 38759-fetch-available-parameters-directly-from-gke-when-creating-a-cluster
Diffstat (limited to 'app/models/project.rb')
| -rw-r--r-- | app/models/project.rb | 231 | 
1 files changed, 170 insertions, 61 deletions
diff --git a/app/models/project.rb b/app/models/project.rb index d4e9e51c7be..32d34f5e9b8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -22,6 +22,7 @@ class Project < ActiveRecord::Base    include DeploymentPlatform    include ::Gitlab::Utils::StrongMemoize    include ChronicDurationAttribute +  include FastDestroyAll::Helpers    extend Gitlab::ConfigHelper @@ -64,9 +65,15 @@ class Project < ActiveRecord::Base    default_value_for :only_allow_merge_if_all_discussions_are_resolved, false    add_authentication_token_field :runners_token + +  before_validation :mark_remote_mirrors_for_removal, if: -> { ActiveRecord::Base.connection.table_exists?(:remote_mirrors) } +    before_save :ensure_runners_token    after_save :update_project_statistics, if: :namespace_id_changed? + +  after_save :create_import_state, if: ->(project) { project.import? && project.import_state.nil? } +    after_create :create_project_feature, unless: :project_feature    after_create :create_ci_cd_settings, @@ -78,6 +85,9 @@ class Project < ActiveRecord::Base    after_update :update_forks_visibility_level    before_destroy :remove_private_deploy_keys + +  use_fast_destroy :build_trace_chunks +    after_destroy -> { run_after_commit { remove_pages } }    after_destroy :remove_exports @@ -157,6 +167,8 @@ class Project < ActiveRecord::Base    has_one :fork_network_member    has_one :fork_network, through: :fork_network_member +  has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project +    # Merge Requests for target project should be removed with it    has_many :merge_requests, foreign_key: 'target_project_id'    has_many :source_of_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest' @@ -220,6 +232,7 @@ class Project < ActiveRecord::Base    # still using `dependent: :destroy` here.    has_many :builds, class_name: 'Ci::Build', inverse_of: :project, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent    has_many :build_trace_section_names, class_name: 'Ci::BuildTraceSectionName' +  has_many :build_trace_chunks, class_name: 'Ci::BuildTraceChunk', through: :builds, source: :trace_chunks    has_many :runner_projects, class_name: 'Ci::RunnerProject'    has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'    has_many :variables, class_name: 'Ci::Variable' @@ -230,23 +243,28 @@ class Project < ActiveRecord::Base    has_many :project_deploy_tokens    has_many :deploy_tokens, through: :project_deploy_tokens -  has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' -    has_one :auto_devops, class_name: 'ProjectAutoDevops'    has_many :custom_attributes, class_name: 'ProjectCustomAttribute'    has_many :project_badges, class_name: 'ProjectBadge' -  has_one :ci_cd_settings, class_name: 'ProjectCiCdSetting' +  has_one :ci_cd_settings, class_name: 'ProjectCiCdSetting', inverse_of: :project, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + +  has_many :remote_mirrors, inverse_of: :project    accepts_nested_attributes_for :variables, allow_destroy: true    accepts_nested_attributes_for :project_feature, update_only: true    accepts_nested_attributes_for :import_data    accepts_nested_attributes_for :auto_devops, update_only: true +  accepts_nested_attributes_for :remote_mirrors, +                                allow_destroy: true, +                                reject_if: ->(attrs) { attrs[:id].blank? && attrs[:url].blank? } +    delegate :name, to: :owner, allow_nil: true, prefix: true    delegate :members, to: :team, prefix: true    delegate :add_user, :add_users, to: :team    delegate :add_guest, :add_reporter, :add_developer, :add_master, :add_role, to: :team +  delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings    # Validations    validates :creator, presence: true, on: :create @@ -331,6 +349,12 @@ class Project < ActiveRecord::Base    scope :with_issues_enabled, -> { with_feature_enabled(:issues) }    scope :with_issues_available_for_user, ->(current_user) { with_feature_available_for_user(:issues, current_user) }    scope :with_merge_requests_enabled, -> { with_feature_enabled(:merge_requests) } +  scope :with_remote_mirrors, -> { joins(:remote_mirrors).where(remote_mirrors: { enabled: true }).distinct } + +  scope :with_group_runners_enabled, -> do +    joins(:ci_cd_settings) +    .where(project_ci_cd_settings: { group_runners_enabled: true }) +  end    enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } @@ -381,55 +405,9 @@ class Project < ActiveRecord::Base    scope :abandoned, -> { where('projects.last_activity_at < ?', 6.months.ago) }    scope :excluding_project, ->(project) { where.not(id: project) } -  scope :import_started, -> { where(import_status: 'started') } - -  state_machine :import_status, initial: :none do -    event :import_schedule do -      transition [:none, :finished, :failed] => :scheduled -    end - -    event :force_import_start do -      transition [:none, :finished, :failed] => :started -    end - -    event :import_start do -      transition scheduled: :started -    end - -    event :import_finish do -      transition started: :finished -    end - -    event :import_fail do -      transition [:scheduled, :started] => :failed -    end - -    event :import_retry do -      transition failed: :started -    end - -    state :scheduled -    state :started -    state :finished -    state :failed - -    after_transition [:none, :finished, :failed] => :scheduled do |project, _| -      project.run_after_commit do -        job_id = add_import_job -        update(import_jid: job_id) if job_id -      end -    end -    after_transition started: :finished do |project, _| -      project.reset_cache_and_import_attrs - -      if Gitlab::ImportSources.importer_names.include?(project.import_type) && project.repo_exists? -        project.run_after_commit do -          Projects::AfterImportService.new(project).execute -        end -      end -    end -  end +  scope :joins_import_state, -> { joins("LEFT JOIN project_mirror_data import_state ON import_state.project_id = projects.id") } +  scope :import_started, -> { joins_import_state.where("import_state.status = 'started' OR projects.import_status = 'started'") }    class << self      # Searches for a list of projects based on the query given in `query`. @@ -659,10 +637,6 @@ class Project < ActiveRecord::Base      external_import? || forked? || gitlab_project_import? || bare_repository_import?    end -  def no_import? -    import_status == 'none' -  end -    def external_import?      import_url.present?    end @@ -675,6 +649,99 @@ class Project < ActiveRecord::Base      import_started? || import_scheduled?    end +  def import_state_args +    { +      status: self[:import_status], +      jid: self[:import_jid], +      last_error: self[:import_error] +    } +  end + +  def ensure_import_state(force: false) +    return if !force && (self[:import_status] == 'none' || self[:import_status].nil?) +    return unless import_state.nil? + +    if persisted? +      create_import_state(import_state_args) + +      update_column(:import_status, 'none') +    else +      build_import_state(import_state_args) + +      self[:import_status] = 'none' +    end +  end + +  def import_schedule +    ensure_import_state(force: true) + +    import_state.schedule +  end + +  def force_import_start +    ensure_import_state(force: true) + +    import_state.force_start +  end + +  def import_start +    ensure_import_state(force: true) + +    import_state.start +  end + +  def import_fail +    ensure_import_state(force: true) + +    import_state.fail_op +  end + +  def import_finish +    ensure_import_state(force: true) + +    import_state.finish +  end + +  def import_jid=(new_jid) +    ensure_import_state(force: true) + +    import_state.jid = new_jid +  end + +  def import_jid +    ensure_import_state + +    import_state&.jid +  end + +  def import_error=(new_error) +    ensure_import_state(force: true) + +    import_state.last_error = new_error +  end + +  def import_error +    ensure_import_state + +    import_state&.last_error +  end + +  def import_status=(new_status) +    ensure_import_state(force: true) + +    import_state.status = new_status +  end + +  def import_status +    ensure_import_state + +    import_state&.status || 'none' +  end + +  def no_import? +    import_status == 'none' +  end +    def import_started?      # import? does SQL work so only run it if it looks like there's an import running      import_status == 'started' && import? @@ -708,6 +775,37 @@ class Project < ActiveRecord::Base      import_type == 'gitea'    end +  def has_remote_mirror? +    remote_mirror_available? && remote_mirrors.enabled.exists? +  end + +  def updating_remote_mirror? +    remote_mirrors.enabled.started.exists? +  end + +  def update_remote_mirrors +    return unless remote_mirror_available? + +    remote_mirrors.enabled.each(&:sync) +  end + +  def mark_stuck_remote_mirrors_as_failed! +    remote_mirrors.stuck.update_all( +      update_status: :failed, +      last_error: 'The remote mirror took to long to complete.', +      last_update_at: Time.now +    ) +  end + +  def mark_remote_mirrors_for_removal +    remote_mirrors.each(&:mark_for_delete_if_blank_url) +  end + +  def remote_mirror_available? +    remote_mirror_available_overridden || +      ::Gitlab::CurrentSettings.mirror_available +  end +    def check_limit      unless creator.can_create_project? || namespace.kind == 'group'        projects_limit = creator.projects_limit @@ -1301,12 +1399,17 @@ class Project < ActiveRecord::Base      @shared_runners ||= shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none    end -  def active_shared_runners -    @active_shared_runners ||= shared_runners.active +  def group_runners +    @group_runners ||= group_runners_enabled? ? Ci::Runner.belonging_to_parent_group_of_project(self.id) : Ci::Runner.none +  end + +  def all_runners +    union = Gitlab::SQL::Union.new([runners, group_runners, shared_runners]) +    Ci::Runner.from("(#{union.to_sql}) ci_runners")    end    def any_runners?(&block) -    active_runners.any?(&block) || active_shared_runners.any?(&block) +    all_runners.active.any?(&block)    end    def valid_runners_token?(token) @@ -1471,7 +1574,7 @@ class Project < ActiveRecord::Base    def rename_repo_notify!      # When we import a project overwriting the original project, there      # is a move operation. In that case we don't want to send the instructions. -    send_move_instructions(full_path_was) unless started? +    send_move_instructions(full_path_was) unless import_started?      expires_full_path_cache      self.old_path_with_namespace = full_path_was @@ -1525,7 +1628,8 @@ class Project < ActiveRecord::Base      return unless import_jid      Gitlab::SidekiqStatus.unset(import_jid) -    update_column(:import_jid, nil) + +    import_state.update_column(:jid, nil)    end    def running_or_pending_build_count(force: false) @@ -1544,7 +1648,8 @@ class Project < ActiveRecord::Base      sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message)      import_fail -    update_column(:import_error, sanitized_message) + +    import_state.update_column(:last_error, sanitized_message)    rescue ActiveRecord::ActiveRecordError => e      Rails.logger.error("Error setting import status to failed: #{e.message}. Original error: #{sanitized_message}")    ensure @@ -1874,6 +1979,10 @@ class Project < ActiveRecord::Base      []    end +  def toggle_ci_cd_settings!(settings_attribute) +    ci_cd_settings.toggle!(settings_attribute) +  end +    def gitlab_deploy_token      @gitlab_deploy_token ||= deploy_tokens.gitlab_deploy_token    end  | 
