diff --git a/CHANGELOG b/CHANGELOG index bf1136afd03ef51f431cfa1de2445383d1e8025b..b03c5466d6c23ac836b3f742cb7f5a6343810a06 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -36,6 +36,7 @@ v 8.12.0 (unreleased) - Add Sentry logging to API calls - Add BroadcastMessage API - Use 'git update-ref' for safer web commits !6130 + - Sort pipelines requested through the API - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling) - Remove unused mixins (ClemMakesApps) - Add search to all issue board lists diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index b0c72cfe4b4fd6da6e4cb569eccb0b99ccecb359..371cc3787fba35c98a064d2e06dd79e034e161fc 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -7,11 +7,10 @@ class Projects::PipelinesController < Projects::ApplicationController def index @scope = params[:scope] - all_pipelines = project.pipelines - @pipelines_count = all_pipelines.count - @running_or_pending_count = all_pipelines.running_or_pending.count - @pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope) - @pipelines = @pipelines.order(id: :desc).page(params[:page]).per(30) + @pipelines = PipelinesFinder.new(project).execute(scope: @scope).page(params[:page]).per(30) + + @running_or_pending_count = PipelinesFinder.new(project).execute(scope: 'running').count + @pipelines_count = PipelinesFinder.new(project).execute.count end def new diff --git a/app/finders/pipelines_finder.rb b/app/finders/pipelines_finder.rb index 641fbf838f143d89cf68ed2ce4b875c91aabc5da..32aea75486deee72a465d8f5959a772d1787df79 100644 --- a/app/finders/pipelines_finder.rb +++ b/app/finders/pipelines_finder.rb @@ -1,30 +1,34 @@ class PipelinesFinder - attr_reader :project + attr_reader :project, :pipelines def initialize(project) @project = project + @pipelines = project.pipelines end - def execute(pipelines, scope) - case scope - when 'running' - pipelines.running_or_pending - when 'branches' - from_ids(pipelines, ids_for_ref(pipelines, branches)) - when 'tags' - from_ids(pipelines, ids_for_ref(pipelines, tags)) - else - pipelines - end + def execute(scope: nil) + scoped_pipelines = + case scope + when 'running' + pipelines.running_or_pending + when 'branches' + from_ids(ids_for_ref(branches)) + when 'tags' + from_ids(ids_for_ref(tags)) + else + pipelines + end + + scoped_pipelines.order(id: :desc) end private - def ids_for_ref(pipelines, refs) + def ids_for_ref(refs) pipelines.where(ref: refs).group(:ref).select('max(id)') end - def from_ids(pipelines, ids) + def from_ids(ids) pipelines.unscoped.where(id: ids) end diff --git a/lib/api/pipelines.rb b/lib/api/pipelines.rb index 2aae75c471d337c6919e4506f5511800c1e8c5be..2a0c8e1f2c0abe9a469d23e27e8dcb445af382e2 100644 --- a/lib/api/pipelines.rb +++ b/lib/api/pipelines.rb @@ -13,11 +13,14 @@ module API params do optional :page, type: Integer, desc: 'Page number of the current request' optional :per_page, type: Integer, desc: 'Number of items per page' + optional :scope, type: String, values: ['running', 'branches', 'tags'], + desc: 'Either running, branches, or tags' end get ':id/pipelines' do authorize! :read_pipeline, user_project - present paginate(user_project.pipelines), with: Entities::Pipeline + pipelines = PipelinesFinder.new(user_project).execute(scope: params[:scope]) + present paginate(pipelines), with: Entities::Pipeline end desc 'Gets a specific pipeline for the project' do diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..7100266ab5553eaa4e38d3349b016d27df3adb5d --- /dev/null +++ b/spec/finders/pipelines_finder_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe PipelinesFinder do + let(:project) { create(:project) } + + let!(:tag_pipeline) { create(:ci_pipeline, project: project, ref: 'v1.0.0') } + let!(:branch_pipeline) { create(:ci_pipeline, project: project) } + + subject { described_class.new(project).execute(params) } + + describe "#execute" do + context 'when a scope is passed' do + context 'when scope is nil' do + let(:params) { { scope: nil } } + + it 'selects all pipelines' do + expect(subject.count).to be 2 + expect(subject).to include tag_pipeline + expect(subject).to include branch_pipeline + end + end + + context 'when selecting branches' do + let(:params) { { scope: 'branches' } } + + it 'excludes tags' do + expect(subject).not_to include tag_pipeline + expect(subject).to include branch_pipeline + end + end + + context 'when selecting tags' do + let(:params) { { scope: 'tags' } } + + it 'excludes branches' do + expect(subject).to include tag_pipeline + expect(subject).not_to include branch_pipeline + end + end + end + + # Scoping to running will speed up the test as it doesn't hit the FS + let(:params) { { scope: 'running' } } + + it 'orders in descending order on ID' do + create(:ci_pipeline, project: project, ref: 'feature') + + expect(subject.map(&:id)).to eq [3, 2, 1] + end + end +end