module Gitlab module Ci class PipelineDuration SegmentStruct = Struct.new(:first, :last) class Segment < SegmentStruct def duration last - first end end def self.from_builds(builds) now = Time.now segments = builds.map do |b| Segment.new(b.started_at || now, b.finished_at || now) end new(segments) end attr_reader :duration, :pending_duration def initialize(segments) process(segments.sort_by(&:first)) end private def process(segments) merged = process_segments(segments) @duration = process_duration(merged) @pending_duration = process_pending_duration(merged, @duration) end def process_segments(segments) if segments.empty? segments else segments.drop(1).inject([segments.first]) do |result, current| merged = try_merge_segment(result.last, current) if merged result[-1] = merged result else result << current end end end end def try_merge_segment(previous, current) if current.first <= previous.last Segment.new(previous.first, [previous.last, current.last].max) end end def process_duration(segments) segments.inject(0) do |result, seg| result + seg.duration end end def process_pending_duration(segments, duration) return 0 if segments.empty? total = segments.last.last - segments.first.first total - duration end end end end