diff options
Diffstat (limited to 'app/models')
33 files changed, 290 insertions, 299 deletions
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index be632930895..671a0fe98cc 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -163,6 +163,8 @@ class ApplicationSetting < ActiveRecord::Base end def self.current + ensure_cache_setup + Rails.cache.fetch(CACHE_KEY) do ApplicationSetting.last end @@ -176,9 +178,16 @@ class ApplicationSetting < ActiveRecord::Base end def self.cached + ensure_cache_setup Rails.cache.fetch(CACHE_KEY) end + def self.ensure_cache_setup + # This is a workaround for a Rails bug that causes attribute methods not + # to be loaded when read from cache: https://github.com/rails/rails/issues/27348 + ApplicationSetting.define_attribute_methods + end + def self.defaults_ce { after_sign_up_text: nil, diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 3722047251d..ad0be70c32a 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -15,7 +15,7 @@ module Ci def persisted_environment @persisted_environment ||= Environment.find_by( name: expanded_environment_name, - project_id: gl_project_id + project: project ) end @@ -223,7 +223,8 @@ module Ci def merge_request merge_requests = MergeRequest.includes(:merge_request_diff) - .where(source_branch: ref, source_project_id: pipeline.gl_project_id) + .where(source_branch: ref, + source_project: pipeline.project) .reorder(iid: :asc) merge_requests.find do |merge_request| @@ -231,10 +232,6 @@ module Ci end end - def project_id - gl_project_id - end - def repo_url auth = "gitlab-ci-token:#{ensure_token!}@" project.http_url_to_repo.sub(/^https?:\/\//) do |prefix| @@ -542,6 +539,16 @@ module Ci Gitlab::Ci::Build::Credentials::Factory.new(self).create! end + def dependencies + depended_jobs = depends_on_builds + + return depended_jobs unless options[:dependencies].present? + + depended_jobs.select do |job| + options[:dependencies].include?(job.name) + end + end + private def update_artifacts_size @@ -561,7 +568,7 @@ module Ci end def unscoped_project - @unscoped_project ||= Project.unscoped.find_by(id: gl_project_id) + @unscoped_project ||= Project.unscoped.find_by(id: project_id) end CI_REGISTRY_USER = 'gitlab-ci-token'.freeze diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 8a5a9aa4adb..f12be98c80c 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -5,9 +5,7 @@ module Ci include Importable include AfterCommitQueue - self.table_name = 'ci_commits' - - belongs_to :project, foreign_key: :gl_project_id + belongs_to :project belongs_to :user has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id @@ -22,6 +20,7 @@ module Ci validate :valid_commit_sha, unless: :importing? after_create :keep_around_commits, unless: :importing? + after_create :refresh_build_status_cache state_machine :status, initial: :created do event :enqueue do @@ -114,6 +113,12 @@ module Ci success.latest(ref).order(id: :desc).first end + def self.latest_successful_for_refs(refs) + success.latest(refs).order(id: :desc).each_with_object({}) do |pipeline, hash| + hash[pipeline.ref] ||= pipeline + end + end + def self.truncate_sha(sha) sha[0...8] end @@ -328,6 +333,7 @@ module Ci when 'manual' then block end end + refresh_build_status_cache end def predefined_variables @@ -369,6 +375,10 @@ module Ci .fabricate! end + def refresh_build_status_cache + Ci::PipelineStatus.new(project, sha: sha, status: status).store_in_cache_if_needed + end + private def pipeline_data diff --git a/app/models/ci/pipeline_status.rb b/app/models/ci/pipeline_status.rb new file mode 100644 index 00000000000..048047d0e34 --- /dev/null +++ b/app/models/ci/pipeline_status.rb @@ -0,0 +1,86 @@ +# This class is not backed by a table in the main database. +# It loads the latest Pipeline for the HEAD of a repository, and caches that +# in Redis. +module Ci + class PipelineStatus + attr_accessor :sha, :status, :project, :loaded + + delegate :commit, to: :project + + def self.load_for_project(project) + new(project).tap do |status| + status.load_status + end + end + + def initialize(project, sha: nil, status: nil) + @project = project + @sha = sha + @status = status + end + + def has_status? + loaded? && sha.present? && status.present? + end + + def load_status + return if loaded? + + if has_cache? + load_from_cache + else + load_from_commit + store_in_cache + end + + self.loaded = true + end + + def load_from_commit + return unless commit + + self.sha = commit.sha + self.status = commit.status + end + + # We only cache the status for the HEAD commit of a project + # This status is rendered in project lists + def store_in_cache_if_needed + return unless sha + return delete_from_cache unless commit + store_in_cache if commit.sha == self.sha + end + + def load_from_cache + Gitlab::Redis.with do |redis| + self.sha, self.status = redis.hmget(cache_key, :sha, :status) + end + end + + def store_in_cache + Gitlab::Redis.with do |redis| + redis.mapped_hmset(cache_key, { sha: sha, status: status }) + end + end + + def delete_from_cache + Gitlab::Redis.with do |redis| + redis.del(cache_key) + end + end + + def has_cache? + Gitlab::Redis.with do |redis| + redis.exists(cache_key) + end + end + + def loaded? + self.loaded + end + + def cache_key + "projects/#{project.id}/build_status" + end + end +end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index edd21f984c8..487ba61bc9c 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -9,7 +9,7 @@ module Ci has_many :builds has_many :runner_projects, dependent: :destroy - has_many :projects, through: :runner_projects, foreign_key: :gl_project_id + has_many :projects, through: :runner_projects has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build' @@ -24,7 +24,7 @@ module Ci scope :owned_or_shared, ->(project_id) do joins('LEFT JOIN ci_runner_projects ON ci_runner_projects.runner_id = ci_runners.id') - .where("ci_runner_projects.gl_project_id = :project_id OR ci_runners.is_shared = true", project_id: project_id) + .where("ci_runner_projects.project_id = :project_id OR ci_runners.is_shared = true", project_id: project_id) end scope :assignable_for, ->(project) do diff --git a/app/models/ci/runner_project.rb b/app/models/ci/runner_project.rb index 234376a7e4c..5f01a0daae9 100644 --- a/app/models/ci/runner_project.rb +++ b/app/models/ci/runner_project.rb @@ -1,10 +1,10 @@ module Ci class RunnerProject < ActiveRecord::Base extend Ci::Model - + belongs_to :runner - belongs_to :project, foreign_key: :gl_project_id + belongs_to :project - validates :runner_id, uniqueness: { scope: :gl_project_id } + validates :runner_id, uniqueness: { scope: :project_id } end end diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index 90473d41c04..cba1d81a861 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -4,7 +4,7 @@ module Ci acts_as_paranoid - belongs_to :project, foreign_key: :gl_project_id + belongs_to :project belongs_to :owner, class_name: "User" has_many :trigger_requests, dependent: :destroy diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index 2c8698d8b5d..6c6586110c5 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -2,11 +2,11 @@ module Ci class Variable < ActiveRecord::Base extend Ci::Model - belongs_to :project, foreign_key: :gl_project_id + belongs_to :project validates :key, presence: true, - uniqueness: { scope: :gl_project_id }, + uniqueness: { scope: :project_id }, length: { maximum: 255 }, format: { with: /\A[a-zA-Z0-9_]+\z/, message: "can contain only letters, digits and '_'." } diff --git a/app/models/commit.rb b/app/models/commit.rb index 0a18986ef26..ce92cc369ad 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -231,6 +231,10 @@ class Commit project.pipelines.where(sha: sha) end + def latest_pipeline + pipelines.last + end + def status(ref = nil) @statuses ||= {} @@ -317,7 +321,14 @@ class Commit end def raw_diffs(*args) - raw.diffs(*args) + use_gitaly = Gitlab::GitalyClient.feature_enabled?(:commit_raw_diffs) + deltas_only = args.last.is_a?(Hash) && args.last[:deltas_only] + + if use_gitaly && !deltas_only + Gitlab::GitalyClient::Commit.diff_from_parent(self, *args) + else + raw.diffs(*args) + end end def diffs(diff_options = nil) diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 7e23e14794f..8c71267da65 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -5,7 +5,7 @@ class CommitStatus < ActiveRecord::Base self.table_name = 'ci_builds' - belongs_to :project, foreign_key: :gl_project_id + belongs_to :project belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id belongs_to :user @@ -133,6 +133,12 @@ class CommitStatus < ActiveRecord::Base false end + # Added in 9.0 to keep backward compatibility for projects exported in 8.17 + # and prior. + def gl_project_id + 'dummy' + end + def detailed_status(current_user) Gitlab::Ci::Status::Factory .new(self, current_user) diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb index 5101cc7e687..0a1a65da05a 100644 --- a/app/models/concerns/has_status.rb +++ b/app/models/concerns/has_status.rb @@ -31,6 +31,7 @@ module HasStatus WHEN (#{builds})=(#{created})+(#{skipped})+(#{pending}) THEN 'pending' WHEN (#{running})+(#{pending})>0 THEN 'running' WHEN (#{manual})>0 THEN 'manual' + WHEN (#{created})>0 THEN 'running' ELSE 'failed' END)" end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 3cf4c67d7e7..e7bd20b322a 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -48,11 +48,13 @@ module Issuable delegate :name, :email, + :public_email, to: :author, prefix: true delegate :name, :email, + :public_email, to: :assignee, allow_nil: true, prefix: true @@ -144,7 +146,8 @@ module Issuable when 'milestone_due_desc' then order_milestone_due_desc when 'downvotes_desc' then order_downvotes_desc when 'upvotes_desc' then order_upvotes_desc - when 'priority' then order_labels_priority(excluded_labels: excluded_labels) + when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels) + when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) when 'position_asc' then order_position_asc else order_by(method) @@ -154,7 +157,28 @@ module Issuable sorted.order(id: :desc) end - def order_labels_priority(excluded_labels: []) + def order_due_date_and_labels_priority(excluded_labels: []) + # The order_ methods also modify the query in other ways: + # + # - For milestones, we add a JOIN. + # - For label priority, we change the SELECT, and add a GROUP BY.# + # + # After doing those, we need to reorder to the order we want. The existing + # ORDER BYs won't work because: + # + # 1. We need milestone due date first. + # 2. We can't ORDER BY a column that isn't in the GROUP BY and doesn't + # have an aggregate function applied, so we do a useless MIN() instead. + # + milestones_due_date = 'MIN(milestones.due_date)' + + order_milestone_due_asc. + order_labels_priority(excluded_labels: excluded_labels, extra_select_columns: [milestones_due_date]). + reorder(Gitlab::Database.nulls_last_order(milestones_due_date, 'ASC'), + Gitlab::Database.nulls_last_order('highest_priority', 'ASC')) + end + + def order_labels_priority(excluded_labels: [], extra_select_columns: []) params = { target_type: name, target_column: "#{table_name}.id", @@ -164,7 +188,12 @@ module Issuable highest_priority = highest_label_priority(params).to_sql - select("#{table_name}.*, (#{highest_priority}) AS highest_priority"). + select_columns = [ + "#{table_name}.*", + "(#{highest_priority}) AS highest_priority" + ] + extra_select_columns + + select(select_columns.join(', ')). group(arel_table[:id]). reorder(Gitlab::Database.nulls_last_order('highest_priority', 'ASC')) end @@ -234,6 +263,7 @@ module Issuable user: user.hook_attrs, project: project.hook_attrs, object_attributes: hook_attrs, + labels: labels.map(&:hook_attrs), # DEPRECATED repository: project.hook_attrs.slice(:name, :url, :description, :homepage) } diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb index 9f6d215ceb3..529fb5ce988 100644 --- a/app/models/concerns/routable.rb +++ b/app/models/concerns/routable.rb @@ -51,11 +51,13 @@ module Routable paths.each do |path| path = connection.quote(path) - where = "(routes.path = #{path})" - if cast_lower - where = "(#{where} OR (LOWER(routes.path) = LOWER(#{path})))" - end + where = + if cast_lower + "(LOWER(routes.path) = LOWER(#{path}))" + else + "(routes.path = #{path})" + end wheres << where end diff --git a/app/models/event.rb b/app/models/event.rb index d7ca8e3c599..5c34844b5d3 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -16,7 +16,7 @@ class Event < ActiveRecord::Base RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour - delegate :name, :email, to: :author, prefix: true, allow_nil: true + delegate :name, :email, :public_email, to: :author, prefix: true, allow_nil: true delegate :title, to: :issue, prefix: true, allow_nil: true delegate :title, to: :merge_request, prefix: true, allow_nil: true delegate :title, to: :note, prefix: true, allow_nil: true diff --git a/app/models/group.rb b/app/models/group.rb index bd0ecae3da4..60274386103 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -207,7 +207,7 @@ class Group < Namespace end def members_with_parents - GroupMember.non_request.where(source_id: ancestors.map(&:id).push(id)) + GroupMember.non_request.where(source_id: ancestors.pluck(:id).push(id)) end def users_with_parents diff --git a/app/models/issue.rb b/app/models/issue.rb index f188dcb673c..c2b261825b2 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -57,10 +57,24 @@ class Issue < ActiveRecord::Base state :opened state :reopened state :closed + + before_transition any => :closed do |issue| + issue.closed_at = Time.zone.now + end + + before_transition closed: any do |issue| + issue.closed_at = nil + end end def hook_attrs - attributes + attrs = { + total_time_spent: total_time_spent, + human_total_time_spent: human_total_time_spent, + human_time_estimate: human_time_estimate + } + + attributes.merge!(attrs) end def self.reference_prefix diff --git a/app/models/label.rb b/app/models/label.rb index f68a8c9cff2..568fa6d44f5 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -169,6 +169,10 @@ class Label < ActiveRecord::Base end end + def hook_attrs + attributes + end + private def issues_count(user, params = {}) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 0f7b8311588..cef8ad76b07 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -7,6 +7,7 @@ class MergeRequest < ActiveRecord::Base belongs_to :target_project, class_name: "Project" belongs_to :source_project, class_name: "Project" + belongs_to :project, foreign_key: :target_project_id belongs_to :merge_user, class_name: "User" has_many :merge_request_diffs, dependent: :destroy @@ -523,7 +524,10 @@ class MergeRequest < ActiveRecord::Base source: source_project.try(:hook_attrs), target: target_project.hook_attrs, last_commit: nil, - work_in_progress: work_in_progress? + work_in_progress: work_in_progress?, + total_time_spent: total_time_spent, + human_total_time_spent: human_total_time_spent, + human_time_estimate: human_time_estimate } if diff_head_commit @@ -537,10 +541,6 @@ class MergeRequest < ActiveRecord::Base target_project != source_project end - def project - target_project - end - # If the merge request closes any issues, save this information in the # `MergeRequestsClosingIssues` model. This is a performance optimization. # Calculating this information for a number of merge requests requires diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 7331000a9f2..c0deb59ec4c 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -5,6 +5,7 @@ class Milestone < ActiveRecord::Base None = MilestoneStruct.new('No Milestone', 'No Milestone', 0) Any = MilestoneStruct.new('Any Milestone', '', -1) Upcoming = MilestoneStruct.new('Upcoming', '#upcoming', -2) + Started = MilestoneStruct.new('Started', '#started', -3) include CacheMarkdownField include InternalId diff --git a/app/models/project.rb b/app/models/project.rb index 8c2dadf4659..da4704554b3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -89,7 +89,6 @@ class Project < ActiveRecord::Base has_one :campfire_service, dependent: :destroy has_one :drone_ci_service, dependent: :destroy has_one :emails_on_push_service, dependent: :destroy - has_one :builds_email_service, dependent: :destroy has_one :pipelines_email_service, dependent: :destroy has_one :irker_service, dependent: :destroy has_one :pivotaltracker_service, dependent: :destroy @@ -159,13 +158,13 @@ class Project < ActiveRecord::Base has_one :project_feature, dependent: :destroy has_one :statistics, class_name: 'ProjectStatistics', dependent: :delete - has_many :commit_statuses, dependent: :destroy, foreign_key: :gl_project_id - has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline', foreign_key: :gl_project_id - has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses - has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id + has_many :commit_statuses, dependent: :destroy + has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline' + has_many :builds, class_name: 'Ci::Build' # the builds are created from the commit_statuses + has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject' has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner' - has_many :variables, dependent: :destroy, class_name: 'Ci::Variable', foreign_key: :gl_project_id - has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :gl_project_id + has_many :variables, dependent: :destroy, class_name: 'Ci::Variable' + has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger' has_many :environments, dependent: :destroy has_many :deployments, dependent: :destroy @@ -197,6 +196,7 @@ class Project < ActiveRecord::Base validates :name, uniqueness: { scope: :namespace_id } validates :path, uniqueness: { scope: :namespace_id } validates :import_url, addressable_url: true, if: :external_import? + validates :import_url, importable_url: true, if: [:external_import?, :import_url_changed?] validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create validate :avatar_type, @@ -881,13 +881,9 @@ class Project < ActiveRecord::Base end def http_url_to_repo(user = nil) - url = web_url + credentials = Gitlab::UrlSanitizer.http_credentials_for_user(user) - if user - url.sub!(%r{\Ahttps?://}) { |protocol| "#{protocol}#{user.username}@" } - end - - "#{url}.git" + Gitlab::UrlSanitizer.new("#{web_url}.git", credentials: credentials).full_url end # Check if current branch name is marked as protected in the system @@ -1209,6 +1205,10 @@ class Project < ActiveRecord::Base end end + def pipeline_status + @pipeline_status ||= Ci::PipelineStatus.load_for_project(self) + end + def mark_import_as_failed(error_message) original_errors = errors.dup sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message) diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb index ebd21e37189..0c526b53d72 100644 --- a/app/models/project_services/builds_email_service.rb +++ b/app/models/project_services/builds_email_service.rb @@ -1,107 +1,11 @@ +# This class is to be removed with 9.1 +# We should also by then remove BuildsEmailService from database class BuildsEmailService < Service - prop_accessor :recipients - boolean_accessor :add_pusher - boolean_accessor :notify_only_broken_builds - validates :recipients, presence: true, if: ->(s) { s.activated? && !s.add_pusher? } - - def initialize_properties - if properties.nil? - self.properties = {} - self.notify_only_broken_builds = true - end - end - - def title - 'Builds emails' - end - - def description - 'Email the builds status to a list of recipients.' - end - def self.to_param 'builds_email' end def self.supported_events - %w(build) - end - - def execute(push_data) - return unless supported_events.include?(push_data[:object_kind]) - return unless should_build_be_notified?(push_data) - - recipients = all_recipients(push_data) - - if recipients.any? - BuildEmailWorker.perform_async( - push_data[:build_id], - recipients, - push_data - ) - end - end - - def can_test? - project.builds.any? - end - - def disabled_title - "Please setup a build on your repository." - end - - def test_data(project = nil, user = nil) - Gitlab::DataBuilder::Build.build(project.builds.last) - end - - def fields - [ - { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' }, - { type: 'checkbox', name: 'add_pusher', label: 'Add pusher to recipients list' }, - { type: 'checkbox', name: 'notify_only_broken_builds' }, - ] - end - - def test(data) - begin - # bypass build status verification when testing - data[:build_status] = "failed" - data[:build_allow_failure] = false - - result = execute(data) - rescue StandardError => error - return { success: false, result: error } - end - - { success: true, result: result } - end - - def should_build_be_notified?(data) - case data[:build_status] - when 'success' - !notify_only_broken_builds? - when 'failed' - !allow_failure?(data) - else - false - end - end - - def allow_failure?(data) - data[:build_allow_failure] == true - end - - def all_recipients(data) - all_recipients = [] - - unless recipients.blank? - all_recipients += recipients.split(',').compact.reject(&:blank?) - end - - if add_pusher? && data[:user][:email] - all_recipients << data[:user][:email] - end - - all_recipients + %w[] end end diff --git a/app/models/project_services/chat_message/build_message.rb b/app/models/project_services/chat_message/build_message.rb deleted file mode 100644 index c776e0a20c4..00000000000 --- a/app/models/project_services/chat_message/build_message.rb +++ /dev/null @@ -1,102 +0,0 @@ -module ChatMessage - class BuildMessage < BaseMessage - attr_reader :sha - attr_reader :ref_type - attr_reader :ref - attr_reader :status - attr_reader :project_name - attr_reader :project_url - attr_reader :user_name - attr_reader :user_url - attr_reader :duration - attr_reader :stage - attr_reader :build_id - attr_reader :build_name - - def initialize(params) - @sha = params[:sha] - @ref_type = params[:tag] ? 'tag' : 'branch' - @ref = params[:ref] - @project_name = params[:project_name] - @project_url = params[:project_url] - @status = params[:commit][:status] - @user_name = params[:commit][:author_name] - @user_url = params[:commit][:author_url] - @duration = params[:commit][:duration] - @stage = params[:build_stage] - @build_name = params[:build_name] - @build_id = params[:build_id] - end - - def pretext - '' - end - - def fallback - format(message) - end - - def attachments - [{ text: format(message), color: attachment_color }] - end - - private - - def message - "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_link} #{humanized_status} on build #{build_link} of stage #{stage} in #{duration} #{'second'.pluralize(duration)}" - end - - def build_url - "#{project_url}/builds/#{build_id}" - end - - def build_link - link(build_name, build_url) - end - - def user_link - link(user_name, user_url) - end - - def format(string) - Slack::Notifier::LinkFormatter.format(string) - end - - def humanized_status - case status - when 'success' - 'passed' - else - status - end - end - - def attachment_color - if status == 'success' - 'good' - else - 'danger' - end - end - - def branch_url - "#{project_url}/commits/#{ref}" - end - - def branch_link - link(ref, branch_url) - end - - def project_link - link(project_name, project_url) - end - - def commit_url - "#{project_url}/commit/#{sha}/builds" - end - - def commit_link - link(Commit.truncate_sha(sha), commit_url) - end - end -end diff --git a/app/models/project_services/chat_notification_service.rb b/app/models/project_services/chat_notification_service.rb index 8468934425f..200be99f36b 100644 --- a/app/models/project_services/chat_notification_service.rb +++ b/app/models/project_services/chat_notification_service.rb @@ -6,7 +6,7 @@ class ChatNotificationService < Service default_value_for :category, 'chat' prop_accessor :webhook, :username, :channel - boolean_accessor :notify_only_broken_builds, :notify_only_broken_pipelines + boolean_accessor :notify_only_broken_pipelines validates :webhook, presence: true, url: true, if: :activated? @@ -16,7 +16,6 @@ class ChatNotificationService < Service if properties.nil? self.properties = {} - self.notify_only_broken_builds = true self.notify_only_broken_pipelines = true end end @@ -27,7 +26,7 @@ class ChatNotificationService < Service def self.supported_events %w[push issue confidential_issue merge_request note tag_push - build pipeline wiki_page] + pipeline wiki_page] end def execute(data) @@ -89,8 +88,6 @@ class ChatNotificationService < Service ChatMessage::MergeMessage.new(data) unless is_update?(data) when "note" ChatMessage::NoteMessage.new(data) - when "build" - ChatMessage::BuildMessage.new(data) if should_build_be_notified?(data) when "pipeline" ChatMessage::PipelineMessage.new(data) if should_pipeline_be_notified?(data) when "wiki_page" @@ -125,17 +122,6 @@ class ChatNotificationService < Service data[:object_attributes][:action] == 'update' end - def should_build_be_notified?(data) - case data[:commit][:status] - when 'success' - !notify_only_broken_builds? - when 'failed' - true - else - false - end - end - def should_pipeline_be_notified?(data) case data[:object_attributes][:status] when 'success' diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index c4142c38b2f..8b181221bb0 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -9,13 +9,13 @@ class HipchatService < Service ].freeze prop_accessor :token, :room, :server, :color, :api_version - boolean_accessor :notify_only_broken_builds, :notify + boolean_accessor :notify_only_broken_pipelines, :notify validates :token, presence: true, if: :activated? def initialize_properties if properties.nil? self.properties = {} - self.notify_only_broken_builds = true + self.notify_only_broken_pipelines = true end end @@ -41,12 +41,12 @@ class HipchatService < Service placeholder: 'Leave blank for default (v2)' }, { type: 'text', name: 'server', placeholder: 'Leave blank for default. https://hipchat.example.com' }, - { type: 'checkbox', name: 'notify_only_broken_builds' }, + { type: 'checkbox', name: 'notify_only_broken_pipelines' }, ] end def self.supported_events - %w(push issue confidential_issue merge_request note tag_push build) + %w(push issue confidential_issue merge_request note tag_push pipeline) end def execute(data) @@ -90,8 +90,8 @@ class HipchatService < Service create_merge_request_message(data) unless is_update?(data) when "note" create_note_message(data) - when "build" - create_build_message(data) if should_build_be_notified?(data) + when "pipeline" + create_pipeline_message(data) if should_pipeline_be_notified?(data) end end @@ -240,28 +240,29 @@ class HipchatService < Service message end - def create_build_message(data) - ref_type = data[:tag] ? 'tag' : 'branch' - ref = data[:ref] - sha = data[:sha] - user_name = data[:commit][:author_name] - status = data[:commit][:status] - duration = data[:commit][:duration] + def create_pipeline_message(data) + pipeline_attributes = data[:object_attributes] + pipeline_id = pipeline_attributes[:id] + ref_type = pipeline_attributes[:tag] ? 'tag' : 'branch' + ref = pipeline_attributes[:ref] + user_name = (data[:user] && data[:user][:name]) || 'API' + status = pipeline_attributes[:status] + duration = pipeline_attributes[:duration] branch_link = "<a href=\"#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>" - commit_link = "<a href=\"#{project_url}/commit/#{CGI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>" + pipeline_url = "<a href=\"#{project_url}/pipelines/#{pipeline_id}\">##{pipeline_id}</a>" - "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" + "#{project_link}: Pipeline #{pipeline_url} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" end def message_color(data) - build_status_color(data) || color || 'yellow' + pipeline_status_color(data) || color || 'yellow' end - def build_status_color(data) - return unless data && data[:object_kind] == 'build' + def pipeline_status_color(data) + return unless data && data[:object_kind] == 'pipeline' - case data[:commit][:status] + case data[:object_attributes][:status] when 'success' 'green' else @@ -294,10 +295,10 @@ class HipchatService < Service end end - def should_build_be_notified?(data) - case data[:commit][:status] + def should_pipeline_be_notified?(data) + case data[:object_attributes][:status] when 'success' - !notify_only_broken_builds? + !notify_only_broken_pipelines? when 'failed' true else diff --git a/app/models/project_services/mattermost_service.rb b/app/models/project_services/mattermost_service.rb index c13538e9fea..1156d050622 100644 --- a/app/models/project_services/mattermost_service.rb +++ b/app/models/project_services/mattermost_service.rb @@ -30,7 +30,6 @@ class MattermostService < ChatNotificationService [ { type: 'text', name: 'webhook', placeholder: 'e.g. http://mattermost_host/hooks/…' }, { type: 'text', name: 'username', placeholder: 'e.g. GitLab' }, - { type: 'checkbox', name: 'notify_only_broken_builds' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' }, ] end diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index 375966b9efc..4d7c81a721f 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -30,7 +30,14 @@ class PrometheusService < MonitoringService end def help - 'Retrieves `container_cpu_usage_seconds_total` and `container_memory_usage_bytes` from the configured Prometheus server. An `environment` label is required on each metric to identify the Environment.' + <<-MD.strip_heredoc + Retrieves the Kubernetes node metrics `container_cpu_usage_seconds_total` + and `container_memory_usage_bytes` from the configured Prometheus server. + + If you are not using [Auto-Deploy](https://docs.gitlab.com/ee/ci/autodeploy/index.html) + or have set up your own Prometheus server, an `environment` label is required on each metric to + [identify the Environment](https://docs.gitlab.com/ce/user/project/integrations/prometheus.html#metrics-and-labels). + MD end def self.to_param diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index da7496573ef..b657db6f9ee 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -29,7 +29,6 @@ class SlackService < ChatNotificationService [ { type: 'text', name: 'webhook', placeholder: 'e.g. https://hooks.slack.com/services/…' }, { type: 'text', name: 'username', placeholder: 'e.g. GitLab' }, - { type: 'checkbox', name: 'notify_only_broken_builds' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' }, ] end diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 539b31780b3..70eef359cdd 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -42,8 +42,11 @@ class ProjectWiki url_to_repo end - def http_url_to_repo - [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('') + def http_url_to_repo(user = nil) + url = "#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git" + credentials = Gitlab::UrlSanitizer.http_credentials_for_user(user) + + Gitlab::UrlSanitizer.new(url, credentials: credentials).full_url end def wiki_base_path diff --git a/app/models/route.rb b/app/models/route.rb index 73574a6206b..41e6eb7cb73 100644 --- a/app/models/route.rb +++ b/app/models/route.rb @@ -21,7 +21,7 @@ class Route < ActiveRecord::Base attributes[:path] = route.path.sub(path_was, path) end - if name_changed? && route.name.present? + if name_changed? && name_was.present? && route.name.present? attributes[:name] = route.name.sub(name_was, name) end diff --git a/app/models/service.rb b/app/models/service.rb index 2f75a2e4e7f..e73f7e5d1a3 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -215,7 +215,6 @@ class Service < ActiveRecord::Base assembla bamboo buildkite - builds_email bugzilla campfire custom_issue_tracker diff --git a/app/models/todo.rb b/app/models/todo.rb index 47789a21133..da3fa7277c2 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -48,8 +48,14 @@ class Todo < ActiveRecord::Base after_save :keep_around_commit class << self + # Priority sorting isn't displayed in the dropdown, because we don't show + # milestones, but still show something if the user has a URL with that + # selected. def sort(method) - method == "priority" ? order_by_labels_priority : order_by(method) + case method.to_s + when 'priority', 'label_priority' then order_by_labels_priority + else order_by(method) + end end # Order by priority depending on which issue/merge request the Todo belongs to diff --git a/app/models/user.rb b/app/models/user.rb index 39c1281179b..8c7ad5d5174 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -877,7 +877,7 @@ class User < ActiveRecord::Base def ci_authorized_runners @ci_authorized_runners ||= begin runner_ids = Ci::RunnerProject. - where("ci_runner_projects.gl_project_id IN (#{ci_projects_union.to_sql})"). + where("ci_runner_projects.project_id IN (#{ci_projects_union.to_sql})"). select(:runner_id) Ci::Runner.specific.where(id: runner_ids) end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 2caebb496db..c771c22f46a 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -149,7 +149,13 @@ class WikiPage end # Returns boolean True or False if this instance - # has been fully saved to disk or not. + # is the latest commit version of the page. + def latest? + !historical? + end + + # Returns boolean True or False if this instance + # has been fully created on disk or not. def persisted? @persisted == true end @@ -220,6 +226,8 @@ class WikiPage end def save(method, *args) + saved = false + project_wiki = wiki if valid? && project_wiki.send(method, *args) @@ -237,10 +245,10 @@ class WikiPage set_attributes @persisted = true + saved = true else errors.add(:base, project_wiki.error_message) if project_wiki.error_message - @persisted = false end - @persisted + saved end end |