Commit 85c88f45 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'projects-controller-show' into 'master'

SQL performance improvements for ProjectsController#show

See merge request gitlab-org/gitlab-ce!14226
parents 2e7fe6ea 72190099
...@@ -453,6 +453,10 @@ module Ci ...@@ -453,6 +453,10 @@ module Ci
.fabricate! .fabricate!
end end
def latest_builds_with_artifacts
@latest_builds_with_artifacts ||= builds.latest.with_artifacts
end
private private
def ci_yaml_from_repo def ci_yaml_from_repo
......
...@@ -1163,6 +1163,23 @@ class Project < ActiveRecord::Base ...@@ -1163,6 +1163,23 @@ class Project < ActiveRecord::Base
pipelines.order(id: :desc).find_by(sha: sha, ref: ref) pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
end end
def latest_successful_pipeline_for_default_branch
if defined?(@latest_successful_pipeline_for_default_branch)
return @latest_successful_pipeline_for_default_branch
end
@latest_successful_pipeline_for_default_branch =
pipelines.latest_successful_for(default_branch)
end
def latest_successful_pipeline_for(ref = nil)
if ref && ref != default_branch
pipelines.latest_successful_for(ref)
else
latest_successful_pipeline_for_default_branch
end
end
def enable_ci def enable_ci
project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED) project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED)
end end
......
- pipeline = local_assigns.fetch(:pipeline) { project.pipelines.latest_successful_for(ref) } - pipeline = local_assigns.fetch(:pipeline) { project.latest_successful_pipeline_for(ref) }
- if !project.empty_repo? && can?(current_user, :download_code, project) - if !project.empty_repo? && can?(current_user, :download_code, project)
.project-action-button.dropdown.inline> .project-action-button.dropdown.inline>
...@@ -26,18 +26,16 @@ ...@@ -26,18 +26,16 @@
%i.fa.fa-download %i.fa.fa-download
%span= _('Download tar') %span= _('Download tar')
- if pipeline - if pipeline && pipeline.latest_builds_with_artifacts.any?
- artifacts = pipeline.builds.latest.with_artifacts %li.dropdown-header Artifacts
- if artifacts.any? - unless pipeline.latest?
%li.dropdown-header Artifacts - latest_pipeline = project.pipeline_for(ref)
- unless pipeline.latest? %li
- latest_pipeline = project.pipeline_for(ref) .unclickable= ci_status_for_statuseable(latest_pipeline)
%li %li.dropdown-header Previous Artifacts
.unclickable= ci_status_for_statuseable(latest_pipeline) - pipeline.latest_builds_with_artifacts.each do |job|
%li.dropdown-header Previous Artifacts %li
- artifacts.each do |job| = link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do
%li %i.fa.fa-download
= link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do %span
%i.fa.fa-download #{s_('DownloadArtifacts|Download')} '#{job.name}'
%span
#{ s_('DownloadArtifacts|Download') } '#{job.name}'
---
title: "Memoize the latest builds of a pipeline on a project's homepage"
merge_request:
author:
type: other
---
title: Memoize pipelines for project download buttons
merge_request:
author:
type: other
...@@ -1439,4 +1439,24 @@ describe Ci::Pipeline, :mailer do ...@@ -1439,4 +1439,24 @@ describe Ci::Pipeline, :mailer do
it_behaves_like 'not sending any notification' it_behaves_like 'not sending any notification'
end end
end end
describe '#latest_builds_with_artifacts' do
let!(:pipeline) { create(:ci_pipeline, :success) }
let!(:build) do
create(:ci_build, :success, :artifacts, pipeline: pipeline)
end
it 'returns the latest builds' do
expect(pipeline.latest_builds_with_artifacts).to eq([build])
end
it 'memoizes the returned relation' do
query_count = ActiveRecord::QueryRecorder
.new { 2.times { pipeline.latest_builds_with_artifacts.to_a } }
.count
expect(query_count).to eq(1)
end
end
end end
...@@ -2682,4 +2682,60 @@ describe Project do ...@@ -2682,4 +2682,60 @@ describe Project do
end end
end end
end end
describe '#latest_successful_builds_for' do
let(:project) { build(:project) }
before do
allow(project).to receive(:default_branch).and_return('master')
end
context 'without a ref' do
it 'returns a pipeline for the default branch' do
expect(project)
.to receive(:latest_successful_pipeline_for_default_branch)
project.latest_successful_pipeline_for
end
end
context 'with the ref set to the default branch' do
it 'returns a pipeline for the default branch' do
expect(project)
.to receive(:latest_successful_pipeline_for_default_branch)
project.latest_successful_pipeline_for(project.default_branch)
end
end
context 'with a ref that is not the default branch' do
it 'returns the latest successful pipeline for the given ref' do
expect(project.pipelines).to receive(:latest_successful_for).with('foo')
project.latest_successful_pipeline_for('foo')
end
end
end
describe '#latest_successful_pipeline_for_default_branch' do
let(:project) { build(:project) }
before do
allow(project).to receive(:default_branch).and_return('master')
end
it 'memoizes and returns the latest successful pipeline for the default branch' do
pipeline = double(:pipeline)
expect(project.pipelines).to receive(:latest_successful_for)
.with(project.default_branch)
.and_return(pipeline)
.once
2.times do
expect(project.latest_successful_pipeline_for_default_branch)
.to eq(pipeline)
end
end
end
end 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