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
.fabricate!
end
def latest_builds_with_artifacts
@latest_builds_with_artifacts ||= builds.latest.with_artifacts
end
private
def ci_yaml_from_repo
......
......@@ -1163,6 +1163,23 @@ class Project < ActiveRecord::Base
pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
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
project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED)
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)
.project-action-button.dropdown.inline>
......@@ -26,18 +26,16 @@
%i.fa.fa-download
%span= _('Download tar')
- if pipeline
- artifacts = pipeline.builds.latest.with_artifacts
- if artifacts.any?
%li.dropdown-header Artifacts
- unless pipeline.latest?
- latest_pipeline = project.pipeline_for(ref)
%li
.unclickable= ci_status_for_statuseable(latest_pipeline)
%li.dropdown-header Previous Artifacts
- artifacts.each do |job|
%li
= link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span
#{ s_('DownloadArtifacts|Download') } '#{job.name}'
- if pipeline && pipeline.latest_builds_with_artifacts.any?
%li.dropdown-header Artifacts
- unless pipeline.latest?
- latest_pipeline = project.pipeline_for(ref)
%li
.unclickable= ci_status_for_statuseable(latest_pipeline)
%li.dropdown-header Previous Artifacts
- pipeline.latest_builds_with_artifacts.each do |job|
%li
= link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do
%i.fa.fa-download
%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
it_behaves_like 'not sending any notification'
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
......@@ -2682,4 +2682,60 @@ describe Project do
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
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