Class: Spill::Report

Inherits:
Data
  • Object
show all
Defined in:
lib/spill/report.rb

Constant Summary collapse

GITHUB_DONE_KINDS =
%i[ pr_opened pr_merged review issue_closed commented ].freeze
LOCAL_STATE_KINDS =
%i[ branch_wip dirty_tree ].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#doingObject (readonly)

Returns the value of attribute doing

Returns:

  • (Object)

    the current value of doing



2
3
4
# File 'lib/spill/report.rb', line 2

def doing
  @doing
end

#doneObject (readonly)

Returns the value of attribute done

Returns:

  • (Object)

    the current value of done



2
3
4
# File 'lib/spill/report.rb', line 2

def done
  @done
end

#exploredObject (readonly)

Returns the value of attribute explored

Returns:

  • (Object)

    the current value of explored



2
3
4
# File 'lib/spill/report.rb', line 2

def explored
  @explored
end

#notesObject (readonly)

Returns the value of attribute notes

Returns:

  • (Object)

    the current value of notes



2
3
4
# File 'lib/spill/report.rb', line 2

def notes
  @notes
end

#quietObject (readonly)

Returns the value of attribute quiet

Returns:

  • (Object)

    the current value of quiet



2
3
4
# File 'lib/spill/report.rb', line 2

def quiet
  @quiet
end

#windowObject (readonly)

Returns the value of attribute window

Returns:

  • (Object)

    the current value of window



2
3
4
# File 'lib/spill/report.rb', line 2

def window
  @window
end

Class Method Details

.build(local:, github:, repos:, window:, repo_map: {}) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/spill/report.rb', line 6

def self.build(local:, github:, repos:, window:, repo_map: {})
  local ||= []
  github_events = github || []
  commits = local.select { |event| event.kind == :commit }
  state = local.select { |event| LOCAL_STATE_KINDS.include?(event.kind) }
  done_github = collapse_opened_and_merged(
    github_events.select { |e| GITHUB_DONE_KINDS.include?(e.kind) }
  )

  done = build_done(commits, done_github, repo_map)
  doing = build_doing(state, github_events, repo_map)

  new(
    window: window,
    done: done,
    doing: doing,
    quiet: repos - (done.map { |g| g[:repo] } + doing.map { |g| g[:repo] }).uniq,
    explored: build_explored(github_events),
    notes: build_notes(github, github_events)
  )
end

.build_doing(state, github_events, repo_map) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/spill/report.rb', line 69

def self.build_doing(state, github_events, repo_map)
  open_prs = github_events.select { |e| e.kind == :pr_open }
  groups = {}

  state.group_by(&:repo).each { |repo, events| groups[repo] = { repo: repo, items: events } }

  open_prs.group_by { |e| repo_map[e.repo.to_s.downcase] || e.repo }.each do |name, events|
    groups[name] ||= { repo: name, items: [] }
    groups[name][:items] += events
  end

  groups.each_value { |g| g[:items] = g[:items].sort_by { |e| doing_sort_key(e) } }
  groups.values.sort_by { |g| g[:repo] }
end

.build_done(commits, done_github, repo_map) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/spill/report.rb', line 46

def self.build_done(commits, done_github, repo_map)
  groups = {}

  commits.group_by(&:repo).each do |repo, events|
    branches = events.group_by(&:ref).map do |branch, list|
      { name: branch, commits: list.sort_by(&:timestamp) }
    end
    groups[repo] = { repo: repo, branches: branches, github: [], last: events.map(&:timestamp).max }
  end

  done_github.group_by { |e| repo_map[e.repo.to_s.downcase] || e.repo }.each do |name, events|
    sorted = events.sort_by(&:timestamp)
    if groups[name]
      groups[name][:github] = sorted
      groups[name][:last] = [ groups[name][:last], sorted.map(&:timestamp).max ].max
    else
      groups[name] = { repo: name, branches: [], github: sorted, last: sorted.map(&:timestamp).max }
    end
  end

  groups.values.sort_by { |g| g[:last] }.reverse
end

.build_explored(github_events) ⇒ Object



92
93
94
95
96
97
98
99
# File 'lib/spill/report.rb', line 92

def self.build_explored(github_events)
  github_events.select { |e| e.kind == :starred }
               .group_by(&:repo)
               .map { |repo, events| [ repo, events.map(&:timestamp).max ] }
               .sort_by { |_repo, time| time }
               .reverse
               .map(&:first)
end

.build_notes(github, github_events) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/spill/report.rb', line 101

def self.build_notes(github, github_events)
  notes = []
  notes << "GitHub: skipped (gh not available)" if github.nil?
  truncated = github_events.find { |e| e.kind == :github_truncated }
  notes << "GitHub: may be incomplete before #{truncated.extra[:oldest].strftime("%b %-d")}" if truncated
  if github_events.any? { |e| e.kind == :github_search_capped }
    notes << "GitHub: search results may be incomplete (capped at 100)"
  end
  notes
end

.collapse_opened_and_merged(events) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/spill/report.rb', line 28

def self.collapse_opened_and_merged(events)
  opened_keys = events.select { |e| e.kind == :pr_opened }.map { |e| [ e.repo, e.ref ] }
  merged_keys = events.select { |e| e.kind == :pr_merged }.map { |e| [ e.repo, e.ref ] }
  paired = (opened_keys & merged_keys).uniq

  survivors = events.reject do |e|
    %i[pr_opened pr_merged].include?(e.kind) && paired.include?([ e.repo, e.ref ])
  end

  collapsed = paired.map do |repo, ref|
    merged = events.find { |e| e.kind == :pr_merged && e.repo == repo && e.ref == ref }
    Event.new(source: :github, kind: :pr_opened_and_merged, repo: merged.repo,
              title: merged.title, ref: merged.ref, timestamp: merged.timestamp)
  end

  survivors + collapsed
end

.doing_sort_key(event) ⇒ Object



84
85
86
87
88
89
90
# File 'lib/spill/report.rb', line 84

def self.doing_sort_key(event)
  case event.kind
  when :dirty_tree then [ 0, "", 0.0 ]
  when :branch_wip then [ 1, event.ref.to_s, 0.0 ]
  when :pr_open then [ 2, "", -event.timestamp.to_f ]
  end
end