1# frozen_string_literal: true
2
3module Gitlab
4  module Ci
5    module Charts
6      class Chart
7        attr_reader :from, :to, :labels, :total, :success, :project, :pipeline_times
8
9        def initialize(project)
10          @labels = []
11          @total = []
12          @success = []
13          @pipeline_times = []
14          @project = project
15
16          collect
17        end
18
19        private
20
21        attr_reader :interval
22
23        # rubocop: disable CodeReuse/ActiveRecord
24        def collect
25          query = project.all_pipelines
26            .where(::Ci::Pipeline.arel_table['created_at'].gteq(@from))
27            .where(::Ci::Pipeline.arel_table['created_at'].lteq(@to))
28
29          totals_count  = grouped_count(query)
30          success_count = grouped_count(query.success)
31
32          current = @from
33          while current <= @to
34            label = current.strftime(@format)
35            @labels  << label
36            @total   << (totals_count[label] || 0)
37            @success << (success_count[label] || 0)
38
39            current += interval_step
40          end
41        end
42        # rubocop: enable CodeReuse/ActiveRecord
43
44        # rubocop: disable CodeReuse/ActiveRecord
45        def grouped_count(query)
46          query
47            .group("date_trunc('#{interval}', #{::Ci::Pipeline.table_name}.created_at)")
48            .count(:created_at)
49            .transform_keys { |date| date.strftime(@format) }
50        end
51        # rubocop: enable CodeReuse/ActiveRecord
52
53        def interval_step
54          @interval_step ||= 1.public_send(interval) # rubocop: disable GitlabSecurity/PublicSend
55        end
56      end
57
58      class YearChart < Chart
59        def initialize(*)
60          @to     = Date.today.end_of_month.end_of_day
61          @from   = (@to - 1.year).beginning_of_month.beginning_of_day
62          @interval = :month
63          @format = '%B %Y'
64
65          super
66        end
67      end
68
69      class MonthChart < Chart
70        def initialize(*)
71          @to     = Date.today.end_of_day
72          @from   = (@to - 1.month).beginning_of_day
73          @interval = :day
74          @format = '%d %B'
75
76          super
77        end
78      end
79
80      class WeekChart < Chart
81        def initialize(*)
82          @to     = Date.today.end_of_day
83          @from   = (@to - 1.week).beginning_of_day
84          @interval = :day
85          @format = '%d %B'
86
87          super
88        end
89      end
90
91      class PipelineTime < Chart
92        def collect
93          commits = project.all_pipelines.last(30)
94
95          commits.each do |commit|
96            @labels << commit.short_sha
97            duration = commit.duration || 0
98            @pipeline_times << (duration / 60)
99          end
100        end
101      end
102    end
103  end
104end
105