Commit 5fbb9e95 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'optimise-pipelines' into 'master'

Optimise pipelines.json

See merge request !10462
parents 197dad2e 37a7b099
......@@ -103,18 +103,13 @@ module Ci
end
def playable?
project.builds_enabled? && has_commands? &&
action? && manual?
action? && manual?
end
def action?
self.when == 'manual'
end
def has_commands?
commands.present?
end
def play(current_user)
# Try to queue a current build
if self.enqueue
......@@ -131,8 +126,7 @@ module Ci
end
def retryable?
project.builds_enabled? && has_commands? &&
(success? || failed? || canceled?)
success? || failed? || canceled?
end
def retried?
......
......@@ -12,6 +12,12 @@ module Ci
has_many :builds, foreign_key: :commit_id
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id
has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
has_many :manual_actions, -> { latest.manual_actions }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :artifacts, -> { latest.with_artifacts_not_expired }, foreign_key: :commit_id, class_name: 'Ci::Build'
delegate :id, to: :project, prefix: true
validates :sha, presence: { unless: :importing? }
......@@ -160,10 +166,6 @@ module Ci
end
end
def artifacts
builds.latest.with_artifacts_not_expired.includes(project: [:namespace])
end
def valid_commit_sha
if self.sha == Gitlab::Git::BLANK_SHA
self.errors.add(:sha, " cant be 00000000 (branch removal)")
......@@ -200,27 +202,22 @@ module Ci
!tag?
end
def manual_actions
builds.latest.manual_actions.includes(project: [:namespace])
end
def stuck?
builds.pending.includes(:project).any?(&:stuck?)
pending_builds.any?(&:stuck?)
end
def retryable?
builds.latest.failed_or_canceled.any?(&:retryable?)
retryable_builds.any?
end
def cancelable?
statuses.cancelable.any?
cancelable_statuses.any?
end
def cancel_running
Gitlab::OptimisticLocking.retry_lock(
statuses.cancelable) do |cancelable|
cancelable.find_each(&:cancel)
end
Gitlab::OptimisticLocking.retry_lock(cancelable_statuses) do |cancelable|
cancelable.find_each(&:cancel)
end
end
def retry_failed(current_user)
......
......@@ -172,6 +172,8 @@ class Project < ActiveRecord::Base
has_many :environments, dependent: :destroy
has_many :deployments, dependent: :destroy
has_many :active_runners, -> { active }, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
accepts_nested_attributes_for :variables, allow_destroy: true
accepts_nested_attributes_for :project_feature
......@@ -1085,15 +1087,15 @@ class Project < ActiveRecord::Base
end
def shared_runners
shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none
@shared_runners ||= shared_runners_available? ? Ci::Runner.shared : Ci::Runner.none
end
def any_runners?(&block)
if runners.active.any?(&block)
return true
end
def active_shared_runners
@active_shared_runners ||= shared_runners.active
end
shared_runners.active.any?(&block)
def any_runners?(&block)
active_runners.any?(&block) || active_shared_runners.any?(&block)
end
def valid_runners_token?(token)
......
......@@ -69,13 +69,13 @@ class PipelineEntity < Grape::Entity
alias_method :pipeline, :object
def can_retry?
pipeline.retryable? &&
can?(request.user, :update_pipeline, pipeline)
can?(request.user, :update_pipeline, pipeline) &&
pipeline.retryable?
end
def can_cancel?
pipeline.cancelable? &&
can?(request.user, :update_pipeline, pipeline)
can?(request.user, :update_pipeline, pipeline) &&
pipeline.cancelable?
end
def detailed_status
......
......@@ -13,7 +13,15 @@ class PipelineSerializer < BaseSerializer
def represent(resource, opts = {})
if resource.is_a?(ActiveRecord::Relation)
resource = resource.includes(project: :namespace)
resource = resource.preload([
:retryable_builds,
:cancelable_statuses,
:trigger_requests,
:project,
{ pending_builds: :project },
{ manual_actions: :project },
{ artifacts: :project }
])
end
if paginated?
......
......@@ -7,9 +7,7 @@ module Ci
raise Gitlab::Access::AccessDeniedError
end
pipeline.builds.latest.failed_or_canceled.find_each do |build|
next unless build.retryable?
pipeline.retryable_builds.find_each do |build|
Ci::RetryBuildService.new(project, current_user)
.reprocess(build)
end
......
---
title: Optimise pipelines.json endpoint
merge_request:
author:
FactoryGirl.define do
factory :ci_trigger_without_token, class: Ci::Trigger do
factory :ci_trigger do
token 'token'
sequence(:token) { |n| "token#{n}" }
factory :ci_trigger_for_trigger_schedule do
token { SecureRandom.hex(15) }
......
......@@ -89,6 +89,11 @@ pipelines:
- statuses
- builds
- trigger_requests
- pending_builds
- retryable_builds
- cancelable_statuses
- manual_actions
- artifacts
statuses:
- project
- pipeline
......@@ -199,6 +204,7 @@ project:
- builds
- runner_projects
- runners
- active_runners
- variables
- triggers
- trigger_schedules
......
......@@ -764,40 +764,6 @@ describe Ci::Build, :models do
end
end
describe '#has_commands?' do
context 'when build has commands' do
let(:build) do
create(:ci_build, commands: 'rspec')
end
it 'has commands' do
expect(build).to have_commands
end
end
context 'when does not have commands' do
context 'when commands are an empty string' do
let(:build) do
create(:ci_build, commands: '')
end
it 'has no commands' do
expect(build).not_to have_commands
end
end
context 'when commands are not set at all' do
let(:build) do
create(:ci_build, commands: nil)
end
it 'has no commands' do
expect(build).not_to have_commands
end
end
end
end
describe '#has_tags?' do
context 'when build has tags' do
subject { create(:ci_build, tag_list: ['tag']) }
......
......@@ -17,8 +17,8 @@ describe Ci::Trigger, models: true do
expect(trigger.token).not_to be_nil
end
it 'does not set an random token if one provided' do
trigger = create(:ci_trigger, project: project)
it 'does not set a random token if one provided' do
trigger = create(:ci_trigger, project: project, token: 'token')
expect(trigger.token).to eq('token')
end
......
......@@ -58,6 +58,7 @@ describe Project, models: true do
it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:runner_projects) }
it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:active_runners) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:pages_domains) }
......
......@@ -93,6 +93,44 @@ describe PipelineSerializer do
end
end
end
context 'number of queries' do
let(:resource) { Ci::Pipeline.all }
let(:project) { create(:empty_project) }
before do
Ci::Pipeline::AVAILABLE_STATUSES.each do |status|
create_pipeline(status)
end
RequestStore.begin!
end
after do
RequestStore.end!
RequestStore.clear!
end
it "verifies number of queries" do
recorded = ActiveRecord::QueryRecorder.new { subject }
expect(recorded.count).to be_within(1).of(50)
expect(recorded.cached_count).to eq(0)
end
def create_pipeline(status)
create(:ci_empty_pipeline, project: project, status: status).tap do |pipeline|
Ci::Build::AVAILABLE_STATUSES.each do |status|
create_build(pipeline, status, status)
end
end
end
def create_build(pipeline, stage, status)
create(:ci_build, :tags, :triggered, :artifacts,
pipeline: pipeline, stage: stage,
name: stage, status: status)
end
end
end
describe '#represent_status' do
......
......@@ -462,7 +462,9 @@ describe Ci::ProcessPipelineService, '#execute', :services do
builds.find_by(name: name).play(user)
end
delegate :manual_actions, to: :pipeline
def manual_actions
pipeline.manual_actions(true)
end
def create_build(name, **opts)
create(:ci_build, :created, pipeline: pipeline, name: name, **opts)
......
module ActiveRecord
class QueryRecorder
attr_reader :log
attr_reader :log, :cached
def initialize(&block)
@log = []
@cached = []
ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block)
end
def callback(name, start, finish, message_id, values)
return if %w(CACHE SCHEMA).include?(values[:name])
@log << values[:sql]
if values[:name]&.include?("CACHE")
@cached << values[:sql]
elsif !values[:name]&.include?("SCHEMA")
@log << values[:sql]
end
end
def count
@log.count
end
def cached_count
@cached.count
end
def log_message
@log.join("\n\n")
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment