diff options
author | Yorick Peterse <yorickpeterse@gmail.com> | 2018-05-08 19:32:59 +0200 |
---|---|---|
committer | Yorick Peterse <yorickpeterse@gmail.com> | 2018-05-11 16:18:18 +0200 |
commit | 0c749bfa32a11bac7c704befc389f84d2b381798 (patch) | |
tree | 98e5616574f05a296a5084572762d51e94e34965 | |
parent | 6177c84014ed5799f8844547d8bbf7cd8d726eed (diff) | |
download | gitlab-ce-0c749bfa32a11bac7c704befc389f84d2b381798.tar.gz |
Preloading of Ci::Pipeline#has_warnings?
This changes Ci::Pipeline#has_warnings? so it supports preloading of the
number of warnings per pipeline. This removes the need for executing a
COUNT(*) query for every pipeline just to see if it has any warnings or
not.
-rw-r--r-- | app/models/ci/pipeline.rb | 13 | ||||
-rw-r--r-- | lib/gitlab/ci/pipeline_data_preloader.rb | 5 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline_data_preloader_spec.rb | 3 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 27 |
4 files changed, 47 insertions, 1 deletions
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 0b90834d415..60972c4fc69 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -402,7 +402,18 @@ module Ci end def has_warnings? - builds.latest.failed_but_allowed.any? + number_of_warnings.positive? + end + + def number_of_warnings + BatchLoader.for(id).batch(default_value: 0) do |pipeline_ids, loader| + Build.where(commit_id: pipeline_ids) + .latest + .failed_but_allowed + .group(:commit_id) + .count + .each { |id, amount| loader.call(id, amount) } + end end def set_config_source diff --git a/lib/gitlab/ci/pipeline_data_preloader.rb b/lib/gitlab/ci/pipeline_data_preloader.rb index 98aaa86d1b8..f065d12ad4e 100644 --- a/lib/gitlab/ci/pipeline_data_preloader.rb +++ b/lib/gitlab/ci/pipeline_data_preloader.rb @@ -14,6 +14,11 @@ module Gitlab # This preloads the author of every commit. We're using "lazy_author" # here since "author" immediately loads the data on the first call. pipeline.commit.try(:lazy_author) + + # This preloads the number of warnings for every pipeline, ensuring + # that Ci::Pipeline#has_warnings? doesn't execute any additional + # queries. + pipeline.number_of_warnings end end end diff --git a/spec/lib/gitlab/ci/pipeline_data_preloader_spec.rb b/spec/lib/gitlab/ci/pipeline_data_preloader_spec.rb index 1aa6fa91edc..11488ff1d32 100644 --- a/spec/lib/gitlab/ci/pipeline_data_preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline_data_preloader_spec.rb @@ -11,6 +11,9 @@ describe Gitlab::Ci::PipelineDataPreloader do expect(commit) .to receive(:lazy_author) + expect(pipeline) + .to receive(:number_of_warnings) + described_class.preload([pipeline]) end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index ddd66a6be87..e7845b693a1 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -774,6 +774,33 @@ describe Ci::Pipeline, :mailer do end end + describe '#number_of_warnings' do + it 'returns the number of warnings' do + create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop') + + expect(pipeline.number_of_warnings).to eq(1) + end + + it 'supports eager loading of the number of warnings' do + pipeline2 = create(:ci_empty_pipeline, status: :created, project: project) + + create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop') + create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline2, name: 'rubocop') + + pipelines = project.pipelines.to_a + + pipelines.each(&:number_of_warnings) + + # To run the queries we need to actually use the lazy objects, which we do + # by just sending "to_i" to them. + amount = ActiveRecord::QueryRecorder + .new { pipelines.each { |p| p.number_of_warnings.to_i } } + .count + + expect(amount).to eq(1) + end + end + shared_context 'with some outdated pipelines' do before do create_pipeline(:canceled, 'ref', 'A', project) |