summaryrefslogtreecommitdiff
path: root/app/models/global_milestone.rb
blob: e13aaf16732d85d87e25973afd5cf25c8982c6ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class GlobalMilestone
  attr_accessor :title, :milestones
  alias_attribute :name, :title

  def self.build_collection(milestones)
    milestones = milestones.group_by(&:title)

    milestones.map do |title, milestones|
      new(title, milestones)
    end
  end

  def initialize(title, milestones)
    @title = title
    @milestones = milestones
  end

  def safe_title
    @title.to_slug.normalize.to_s
  end

  def expired?
    if due_date
      due_date.past?
    else
      false
    end
  end

  def projects
    @projects ||= Project.for_milestones(milestones.map(&:id))
  end

  def issues_count
    issues.count
  end

  def merge_requests_count
    merge_requests.count
  end

  def open_items_count
    opened_issues.count + opened_merge_requests.count
  end

  def closed_items_count
    closed_issues.count + closed_merge_requests.count
  end

  def total_items_count
    issues_count + merge_requests_count
  end

  def percent_complete
    ((closed_items_count * 100) / total_items_count).abs
  rescue ZeroDivisionError
    0
  end

  def state
    state = milestones.map { |milestone| milestone.state }

    if state.count('closed') == state.size
      'closed'
    else
      'active'
    end
  end

  def active?
    state == 'active'
  end

  def closed?
    state == 'closed'
  end

  def issues
    @issues ||= Issue.of_milestones(milestones.map(&:id)).includes(:project)
  end

  def merge_requests
    @merge_requests ||= MergeRequest.of_milestones(milestones.map(&:id)).includes(:target_project)
  end

  def participants
    @participants ||= milestones.map(&:participants).flatten.compact.uniq
  end

  def labels
    @labels ||= milestones.map do |ms|
                  ms.labels.map { |label| LabelWithMilestone.new(label, ms) }
                end.flatten.sort_by!(&:title)
  end

  def opened_issues
    issues.opened
  end

  def closed_issues
    issues.closed
  end

  def opened_merge_requests
    merge_requests.opened
  end

  def closed_merge_requests
    merge_requests.with_states(:closed, :merged, :locked)
  end

  def complete?
    total_items_count == closed_items_count
  end

  def due_date
    return @due_date if defined?(@due_date)

    @due_date =
      if @milestones.all? { |x| x.due_date == @milestones.first.due_date }
        @milestones.first.due_date
      else
        nil
      end
  end

  def expires_at
    if due_date
      if due_date.past?
        "expired on #{due_date.to_s(:medium)}"
      else
        "expires on #{due_date.to_s(:medium)}"
      end
    end
  end
end