gitlab-org--gitlab-foss/app/controllers/projects/pipelines_controller.rb
Stan Hu f2fa7c3299 Fix and expand Gitaly FindCommit caching
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26248 added
support for deduplicating FindCommit requests using Gitaly ref name
caching. However, not all endpoints were covered, and in one case the
Gitaly wrapper wasn't actually surrounding the serialization step. We
can safely cache ref names between FindCommit calls for #index and #show
endpoints for merge requests and pipelines. This can significantly
reduce the number of FindCommit requests.
2019-04-04 13:42:58 -07:00

199 lines
5.3 KiB
Ruby

# frozen_string_literal: true
class Projects::PipelinesController < Projects::ApplicationController
before_action :whitelist_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts]
before_action :authorize_read_pipeline!
before_action :authorize_read_build!, only: [:index]
before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
wrap_parameters Ci::Pipeline
POLLING_INTERVAL = 10_000
def index
@scope = params[:scope]
@pipelines = PipelinesFinder
.new(project, current_user, scope: @scope)
.execute
.page(params[:page])
.per(30)
@running_count = limited_pipelines_count(project, 'running')
@pending_count = limited_pipelines_count(project, 'pending')
@finished_count = limited_pipelines_count(project, 'finished')
@pipelines_count = limited_pipelines_count(project)
respond_to do |format|
format.html
format.json do
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
render json: {
pipelines: serialize_pipelines,
count: {
all: @pipelines_count,
running: @running_count,
pending: @pending_count,
finished: @finished_count
}
}
end
end
end
def new
@pipeline = project.all_pipelines.new(ref: @project.default_branch)
end
def create
@pipeline = Ci::CreatePipelineService
.new(project, current_user, create_params)
.execute(:web, ignore_skip_ci: true, save_on_errors: false)
if @pipeline.persisted?
redirect_to project_pipeline_path(project, @pipeline)
else
render 'new'
end
end
def show
respond_to do |format|
format.html
format.json do
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
render json: PipelineSerializer
.new(project: @project, current_user: @current_user)
.represent(@pipeline, show_represent_params)
end
end
end
def builds
render_show
end
def failures
if @pipeline.failed_builds.present?
render_show
else
redirect_to pipeline_path(@pipeline)
end
end
def status
render json: PipelineSerializer
.new(project: @project, current_user: @current_user)
.represent_status(@pipeline)
end
def stage
@stage = pipeline.legacy_stage(params[:stage])
return not_found unless @stage
render json: StageSerializer
.new(project: @project, current_user: @current_user)
.represent(@stage, details: true, retried: params[:retried])
end
# TODO: This endpoint is used by mini-pipeline-graph
# TODO: This endpoint should be migrated to `stage.json`
def stage_ajax
@stage = pipeline.legacy_stage(params[:stage])
return not_found unless @stage
render json: { html: view_to_html_string('projects/pipelines/_stage') }
end
def retry
pipeline.retry_failed(current_user)
respond_to do |format|
format.html do
redirect_back_or_default default: project_pipelines_path(project)
end
format.json { head :no_content }
end
end
def cancel
pipeline.cancel_running
respond_to do |format|
format.html do
redirect_back_or_default default: project_pipelines_path(project)
end
format.json { head :no_content }
end
end
def charts
@charts = {}
@charts[:week] = Gitlab::Ci::Charts::WeekChart.new(project)
@charts[:month] = Gitlab::Ci::Charts::MonthChart.new(project)
@charts[:year] = Gitlab::Ci::Charts::YearChart.new(project)
@charts[:pipeline_times] = Gitlab::Ci::Charts::PipelineTime.new(project)
@counts = {}
@counts[:total] = @project.all_pipelines.count(:all)
@counts[:success] = @project.all_pipelines.success.count(:all)
@counts[:failed] = @project.all_pipelines.failed.count(:all)
end
private
def serialize_pipelines
PipelineSerializer
.new(project: @project, current_user: @current_user)
.with_pagination(request, response)
.represent(@pipelines, disable_coverage: true, preload: true)
end
def render_show
respond_to do |format|
format.html do
render 'show'
end
end
end
def show_represent_params
{ grouped: true }
end
def create_params
params.require(:pipeline).permit(:ref, variables_attributes: %i[key secret_value])
end
# rubocop: disable CodeReuse/ActiveRecord
def pipeline
@pipeline ||= project
.all_pipelines
.includes(user: :status)
.find_by!(id: params[:id])
.present(current_user: current_user)
end
# rubocop: enable CodeReuse/ActiveRecord
def whitelist_query_limiting
# Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42343
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42339')
end
def authorize_update_pipeline!
return access_denied! unless can?(current_user, :update_pipeline, @pipeline)
end
def limited_pipelines_count(project, scope = nil)
finder = PipelinesFinder.new(project, current_user, scope: scope)
view_context.limited_counter_with_delimiter(finder.execute)
end
end