diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/blob_viewer/gitlab_ci_yml.rb | 8 | ||||
-rw-r--r-- | app/models/ci/build.rb | 52 | ||||
-rw-r--r-- | app/models/ci/build_metadata.rb | 12 | ||||
-rw-r--r-- | app/models/ci/pipeline.rb | 10 | ||||
-rw-r--r-- | app/models/ci/runner.rb | 4 | ||||
-rw-r--r-- | app/models/clusters/applications/knative.rb | 11 | ||||
-rw-r--r-- | app/models/clusters/platforms/kubernetes.rb | 2 | ||||
-rw-r--r-- | app/models/list.rb | 2 | ||||
-rw-r--r-- | app/models/project.rb | 67 | ||||
-rw-r--r-- | app/models/release.rb | 14 | ||||
-rw-r--r-- | app/models/releases/link.rb | 22 | ||||
-rw-r--r-- | app/models/releases/source.rb | 35 |
12 files changed, 192 insertions, 47 deletions
diff --git a/app/models/blob_viewer/gitlab_ci_yml.rb b/app/models/blob_viewer/gitlab_ci_yml.rb index 655241c2808..11228e620c9 100644 --- a/app/models/blob_viewer/gitlab_ci_yml.rb +++ b/app/models/blob_viewer/gitlab_ci_yml.rb @@ -10,16 +10,16 @@ module BlobViewer self.file_types = %i(gitlab_ci) self.binary = false - def validation_message(project, sha) + def validation_message(opts) return @validation_message if defined?(@validation_message) prepare! - @validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data, { project: project, sha: sha }) + @validation_message = Gitlab::Ci::YamlProcessor.validation_message(blob.data, opts) end - def valid?(project, sha) - validation_message(project, sha).blank? + def valid?(opts) + validation_message(opts).blank? end end end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index aeb35538d67..dc6f8ae1a7f 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -8,10 +8,15 @@ module Ci include ObjectStorage::BackgroundMove include Presentable include Importable + include IgnorableColumn include Gitlab::Utils::StrongMemoize include Deployable include HasRef + BuildArchivedError = Class.new(StandardError) + + ignore_column :commands + belongs_to :project, inverse_of: :builds belongs_to :runner belongs_to :trigger_request @@ -31,7 +36,7 @@ module Ci has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id end - has_one :metadata, class_name: 'Ci::BuildMetadata' + has_one :metadata, class_name: 'Ci::BuildMetadata', autosave: true has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build accepts_nested_attributes_for :runner_session @@ -273,11 +278,14 @@ module Ci # degenerated build is one that cannot be run by Runner def degenerated? - self.options.nil? + self.options.blank? end def degenerate! - self.update!(options: nil, yaml_variables: nil, commands: nil) + Build.transaction do + self.update!(options: nil, yaml_variables: nil) + self.metadata&.destroy + end end def archived? @@ -624,11 +632,23 @@ module Ci end def when - read_attribute(:when) || build_attributes_from_config[:when] || 'on_success' + read_attribute(:when) || 'on_success' + end + + def options + read_metadata_attribute(:options, :config_options, {}) end def yaml_variables - read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || [] + read_metadata_attribute(:yaml_variables, :config_variables, []) + end + + def options=(value) + write_metadata_attribute(:options, :config_options, value) + end + + def yaml_variables=(value) + write_metadata_attribute(:yaml_variables, :config_variables, value) end def user_variables @@ -904,8 +924,11 @@ module Ci # have the old integer only format. This method returns the retry option # normalized as a hash in 11.5+ format. def normalized_retry - value = options&.dig(:retry) - value.is_a?(Integer) ? { max: value } : value.to_h + strong_memoize(:normalized_retry) do + value = options&.dig(:retry) + value = value.is_a?(Integer) ? { max: value } : value.to_h + value.with_indifferent_access + end end def build_attributes_from_config @@ -929,5 +952,20 @@ module Ci def project_destroyed? project.pending_delete? end + + def read_metadata_attribute(legacy_key, metadata_key, default_value = nil) + read_attribute(legacy_key) || metadata&.read_attribute(metadata_key) || default_value + end + + def write_metadata_attribute(legacy_key, metadata_key, value) + # save to metadata or this model depending on the state of feature flag + if Feature.enabled?(:ci_build_metadata_config) + ensure_metadata.write_attribute(metadata_key, value) + write_attribute(legacy_key, nil) + else + write_attribute(legacy_key, value) + metadata&.write_attribute(metadata_key, nil) + end + end end end diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb index 9d588b862bd..38390f49217 100644 --- a/app/models/ci/build_metadata.rb +++ b/app/models/ci/build_metadata.rb @@ -13,8 +13,12 @@ module Ci belongs_to :build, class_name: 'Ci::Build' belongs_to :project + before_create :set_build_project + validates :build, presence: true - validates :project, presence: true + + serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize + serialize :config_variables, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize chronic_duration_attr_reader :timeout_human_readable, :timeout @@ -33,5 +37,11 @@ module Ci update(timeout: timeout, timeout_source: timeout_source) end + + private + + def set_build_project + self.project_id ||= self.build.project_id + end end end diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 5b446e649a9..30a957b4117 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -509,7 +509,7 @@ module Ci return @config_processor if defined?(@config_processor) @config_processor ||= begin - ::Gitlab::Ci::YamlProcessor.new(ci_yaml_file, { project: project, sha: sha }) + ::Gitlab::Ci::YamlProcessor.new(ci_yaml_file, { project: project, sha: sha, user: user }) rescue Gitlab::Ci::YamlProcessor::ValidationError => e self.yaml_errors = e.message nil @@ -648,7 +648,7 @@ module Ci def all_merge_requests @all_merge_requests ||= if merge_request? - project.merge_requests.where(id: merge_request.id) + project.merge_requests.where(id: merge_request_id) else project.merge_requests.where(source_branch: ref) end @@ -727,6 +727,12 @@ module Ci def git_ref if merge_request? + ## + # In the future, we're going to change this ref to + # merge request's merged reference, such as "refs/merge-requests/:iid/merge". + # In order to do that, we have to update GitLab-Runner's source pulling + # logic. + # See https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1092 Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s else super diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 8249199e76f..5aae31de6e2 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -256,6 +256,10 @@ module Ci end end + def uncached_contacted_at + read_attribute(:contacted_at) + end + private def cleanup_runner_queue diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index 0a3168afe68..c572c8bff44 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -19,6 +19,13 @@ module Clusters self.reactive_cache_key = ->(knative) { [knative.class.model_name.singular, knative.id] } + def set_initial_status + return unless not_installable? + return unless verify_cluster? + + self.status = 'installable' + end + state_machine :status do after_transition any => [:installed] do |application| application.run_after_commit do @@ -99,6 +106,10 @@ module Clusters def install_knative_metrics ["kubectl apply -f #{METRICS_CONFIG}"] if cluster.application_prometheus_available? end + + def verify_cluster? + cluster&.application_helm_available? && cluster&.platform_kubernetes_rbac? + end end end end diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 0dc0c4f80d6..1cc170c8c4d 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -65,6 +65,8 @@ module Clusters abac: 2 } + default_value_for :authorization_type, :rbac + def actual_namespace if namespace.present? namespace diff --git a/app/models/list.rb b/app/models/list.rb index 029685be927..682af761ba0 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -54,6 +54,6 @@ class List < ActiveRecord::Base private def can_be_destroyed - destroyable? + throw(:abort) unless destroyable? end end diff --git a/app/models/project.rb b/app/models/project.rb index cd558752080..e2f010a0432 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -330,8 +330,8 @@ class Project < ActiveRecord::Base validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? } - validate :visibility_level_allowed_by_group - validate :visibility_level_allowed_as_fork + validate :visibility_level_allowed_by_group, if: -> { changes.has_key?(:visibility_level) } + validate :visibility_level_allowed_as_fork, if: -> { changes.has_key?(:visibility_level) } validate :check_wiki_path_conflict validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) } validates :repository_storage, @@ -912,11 +912,16 @@ class Project < ActiveRecord::Base def new_issuable_address(author, address_type) return unless Gitlab::IncomingEmail.supports_issue_creation? && author + # check since this can come from a request parameter + return unless %w(issue merge_request).include?(address_type) + author.ensure_incoming_email_token! - suffix = address_type == 'merge_request' ? '+merge-request' : '' - Gitlab::IncomingEmail.reply_address( - "#{full_path}#{suffix}+#{author.incoming_email_token}") + suffix = address_type.dasherize + + # example: incoming+h5bp-html5-boilerplate-8-1234567890abcdef123456789-issue@localhost.com + # example: incoming+h5bp-html5-boilerplate-8-1234567890abcdef123456789-merge-request@localhost.com + Gitlab::IncomingEmail.reply_address("#{full_path_slug}-#{project_id}-#{author.incoming_email_token}-#{suffix}") end def build_commit_note(commit) @@ -1700,6 +1705,13 @@ class Project < ActiveRecord::Base .append(key: 'CI_PROJECT_VISIBILITY', value: visibility) .concat(container_registry_variables) .concat(auto_devops_variables) + .concat(api_variables) + end + + def api_variables + Gitlab::Ci::Variables::Collection.new.tap do |variables| + variables.append(key: 'CI_API_V4_URL', value: API::Helpers::Version.new('v4').root_url) + end end def container_registry_variables @@ -1928,23 +1940,15 @@ class Project < ActiveRecord::Base .where('project_authorizations.project_id = merge_requests.target_project_id') .limit(1) .select(1) - source_of_merge_requests.opened - .where(allow_collaboration: true) - .where('EXISTS (?)', developer_access_exists) + merge_requests_allowing_collaboration.where('EXISTS (?)', developer_access_exists) end - def branch_allows_collaboration?(user, branch_name) - return false unless user - - cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push" - - memoized_results = strong_memoize(:branch_allows_collaboration) do - Hash.new do |result, cache_key| - result[cache_key] = fetch_branch_allows_collaboration?(user, branch_name) - end - end + def any_branch_allows_collaboration?(user) + fetch_branch_allows_collaboration(user) + end - memoized_results[cache_key] + def branch_allows_collaboration?(user, branch_name) + fetch_branch_allows_collaboration(user, branch_name) end def licensed_features @@ -2018,6 +2022,12 @@ class Project < ActiveRecord::Base private + def merge_requests_allowing_collaboration(source_branch = nil) + relation = source_of_merge_requests.opened.where(allow_collaboration: true) + relation = relation.where(source_branch: source_branch) if source_branch + relation + end + def create_new_pool_repository pool = begin create_pool_repository!(shard: Shard.by_name(repository_storage), source_project: self) @@ -2142,26 +2152,19 @@ class Project < ActiveRecord::Base raise ex end - def fetch_branch_allows_collaboration?(user, branch_name) - check_access = -> do - next false if empty_repo? + def fetch_branch_allows_collaboration(user, branch_name = nil) + return false unless user - merge_requests = source_of_merge_requests.opened - .where(allow_collaboration: true) + Gitlab::SafeRequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do + next false if empty_repo? # Issue for N+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/49322 Gitlab::GitalyClient.allow_n_plus_1_calls do - if branch_name - merge_requests.find_by(source_branch: branch_name)&.can_be_merged_by?(user) - else - merge_requests.any? { |merge_request| merge_request.can_be_merged_by?(user) } + merge_requests_allowing_collaboration(branch_name).any? do |merge_request| + merge_request.can_be_merged_by?(user) end end end - - Gitlab::SafeRequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do - check_access.call - end end def services_templates diff --git a/app/models/release.rb b/app/models/release.rb index df3dfe1cf2f..0dae5c90394 100644 --- a/app/models/release.rb +++ b/app/models/release.rb @@ -10,6 +10,10 @@ class Release < ActiveRecord::Base # releases prior to 11.7 have no author belongs_to :author, class_name: 'User' + has_many :links, class_name: 'Releases::Link' + + accepts_nested_attributes_for :links, allow_destroy: true + validates :description, :project, :tag, presence: true scope :sorted, -> { order(created_at: :desc) } @@ -26,6 +30,16 @@ class Release < ActiveRecord::Base actual_tag.nil? end + def assets_count + links.count + sources.count + end + + def sources + strong_memoize(:sources) do + Releases::Source.all(project, tag) + end + end + private def actual_sha diff --git a/app/models/releases/link.rb b/app/models/releases/link.rb new file mode 100644 index 00000000000..766cb2efff2 --- /dev/null +++ b/app/models/releases/link.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Releases + class Link < ActiveRecord::Base + self.table_name = 'release_links' + + belongs_to :release + + validates :url, presence: true, url: true + validates :name, presence: true, uniqueness: { scope: :release } + + scope :sorted, -> { order(created_at: :desc) } + + def internal? + url.start_with?(release.project.web_url) + end + + def external? + !internal? + end + end +end diff --git a/app/models/releases/source.rb b/app/models/releases/source.rb new file mode 100644 index 00000000000..4d3d54457af --- /dev/null +++ b/app/models/releases/source.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Releases + class Source + include ActiveModel::Model + + attr_accessor :project, :tag_name, :format + + FORMATS = %w(zip tar.gz tar.bz2 tar).freeze + + class << self + def all(project, tag_name) + Releases::Source::FORMATS.map do |format| + Releases::Source.new(project: project, + tag_name: tag_name, + format: format) + end + end + end + + def url + Gitlab::Routing + .url_helpers + .project_archive_url(project, + id: File.join(tag_name, archive_prefix), + format: format) + end + + private + + def archive_prefix + "#{project.path}-#{tag_name.tr('/', '-')}" + end + end +end |