Class: Exporter

Inherits:
Object show all
Defined in:
lib/jirametrics/exporter.rb,
lib/jirametrics/examples/standard_project.rb,
lib/jirametrics/examples/aggregated_project.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeExporter

Returns a new instance of Exporter.



46
47
48
49
50
51
52
# File 'lib/jirametrics/exporter.rb', line 46

def initialize
  @project_configs = []
  @timezone_offset = '+00:00'
  @target_path = '.'
  @holiday_dates = []
  @downloading = false
end

Instance Attribute Details

#project_configsObject (readonly)

Returns the value of attribute project_configs.



36
37
38
# File 'lib/jirametrics/exporter.rb', line 36

def project_configs
  @project_configs
end

Class Method Details

.configure(&block) ⇒ Object



38
39
40
41
42
# File 'lib/jirametrics/exporter.rb', line 38

def self.configure &block
  exporter = Exporter.new
  exporter.instance_eval(&block)
  @@instance = exporter
end

.instanceObject



44
# File 'lib/jirametrics/exporter.rb', line 44

def self.instance = @@instance

Instance Method Details

#aggregated_project(name:, project_names:) ⇒ Object



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
# File 'lib/jirametrics/examples/aggregated_project.rb', line 4

def aggregated_project name:, project_names:
  project name: name do
    puts name
    aggregate do
      project_names.each do |project_name|
        include_issues_from project_name
      end
    end

    file_prefix name

    file do
      file_suffix '.html'
      issues.reject! do |issue|
        %w[Sub-task Epic].include? issue.type
      end

      html_report do
        cycletime_scatterplot do
          show_trend_lines
          grouping_rules do |issue, rules|
            rules.label = issue.board.name
          end
        end
        aging_work_in_progress_chart
        aging_work_table do
          age_cutoff 21
        end
      end
    end
  end
end

#download(name_filter:) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/jirametrics/exporter.rb', line 61

def download name_filter:
  @downloading = true
  logfile_name = 'downloader.log'
  File.open logfile_name, 'w' do |logfile|
    each_project_config(name_filter: name_filter) do |project|
      project.evaluate_next_level
      next if project.aggregated_project?

      project.download_config.run
      downloader = Downloader.new(download_config: project.download_config)
      downloader.logfile = logfile
      downloader.logfile_name = logfile_name
      downloader.run
    end
  end
  puts "Full output from downloader in #{logfile_name}"
end

#downloading?Boolean

Returns:

  • (Boolean)


85
86
87
# File 'lib/jirametrics/exporter.rb', line 85

def downloading?
  @downloading
end

#each_project_config(name_filter:) ⇒ Object



79
80
81
82
83
# File 'lib/jirametrics/exporter.rb', line 79

def each_project_config name_filter:
  @project_configs.each do |project|
    yield project if project.name.nil? || File.fnmatch(name_filter, project.name)
  end
end

#export(name_filter:) ⇒ Object



54
55
56
57
58
59
# File 'lib/jirametrics/exporter.rb', line 54

def export name_filter:
  each_project_config(name_filter: name_filter) do |project|
    project.evaluate_next_level
    project.run
  end
end

#holiday_dates(*args) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/jirametrics/exporter.rb', line 119

def holiday_dates *args
  unless args.empty?
    dates = []
    args.each do |arg|
      if arg =~ /^(\d{4}-\d{2}-\d{2})\.\.(\d{4}-\d{2}-\d{2})$/
        Date.parse($1).upto(Date.parse($2)).each { |date| dates << date }
      else
        dates << Date.parse(arg)
      end
    end
    @holiday_dates = dates
  end
  @holiday_dates
end

#jira_config(filename = nil) ⇒ Object



109
110
111
112
# File 'lib/jirametrics/exporter.rb', line 109

def jira_config filename = nil
  @jira_config = JsonFileLoader.new.load(filename) unless filename.nil?
  @jira_config
end

#project(name: nil, &block) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/jirametrics/exporter.rb', line 89

def project name: nil, &block
  raise 'target_path was never set!' if @target_path.nil?
  raise 'jira_config not set' if @jira_config.nil?

  @project_configs << ProjectConfig.new(
    exporter: self, target_path: @target_path, jira_config: @jira_config, block: block, name: name
  )
end

#standard_project(name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {}, default_board: nil) ⇒ Object



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
# File 'lib/jirametrics/examples/standard_project.rb', line 4

def standard_project name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {}, default_board: nil
  project name: name do
    puts name

    settings['blocked_link_text'] = ['is blocked by']
    file_prefix file_prefix
    download do
      rolling_date_count 90
    end

    boards.each_key do |board_id|
      block = boards[board_id]
      if block == :default
        block = lambda do |_|
          start_at first_time_in_status_category('In Progress')
          stop_at still_in_status_category('Done')
        end
      end
      board id: board_id do
        cycletime(&block)
        expedited_priority_names 'Critical', 'Highest', 'Immediate Gating'
      end
    end

    file do
      file_suffix '.html'
      issues.reject! do |issue|
        %w[Sub-task Epic].include? issue.type
      end

      issues.reject! { |issue| ignore_issues.include? issue.key } if ignore_issues

      html_report do
        board_id default_board if default_board

        html "<H1>#{file_prefix}</H1>", type: :header
        boards.each_key do |id|
          board = find_board id
          html "<div><a href='#{board.url}'>#{id} #{board.name}</a></div>",
               type: :header
        end

        discard_changes_before status_becomes: (starting_status || :backlog)

        cycletime_scatterplot do
          show_trend_lines
        end
        cycletime_scatterplot do # Epics
          header_text 'Parents only'
          filter_issues { |i| i.parent }
        end
        cycletime_histogram
        cycletime_histogram do
          grouping_rules do |issue, rules|
            rules.label = issue.board.cycletime.stopped_time(issue).to_date.strftime('%b %Y')
          end
        end

        throughput_chart do
          description_text '<h2>Number of items completed, grouped by issue type</h2>'
        end
        throughput_chart do
          header_text nil
          description_text '<h2>Number of items completed, grouped by completion status and resolution</h2>'
          grouping_rules do |issue, rules|
            if issue.resolution
              rules.label = "#{issue.status.name}:#{issue.resolution}"
            else
              rules.label = issue.status.name
            end
          end
        end

        aging_work_in_progress_chart
        aging_work_bar_chart
        aging_work_table
        daily_wip_by_age_chart
        daily_wip_by_blocked_stalled_chart
        expedited_chart
        sprint_burndown
        story_point_accuracy_chart
        # story_point_accuracy_chart do
        #   header_text nil
        #   description_text nil
        #   y_axis(sort_order: %w[Story Task Defect], label: 'TShirt Sizes') { |issue, _started_time| issue.type }
        # end

        dependency_chart do
          link_rules do |link, rules|
            case link.name
            when 'Cloners'
              rules.ignore
            when 'Dependency', 'Blocks', 'Parent/Child', 'Cause', 'Satisfy Requirement', 'Relates'
              rules.merge_bidirectional keep: 'outward'
              rules.merge_bidirectional keep: 'outward'
            when 'Sync'
              rules.use_bidirectional_arrows
              #   rules.line_color = 'red'
            else
              puts "name=#{link.name}, label=#{link.label}"
            end
          end
        end
      end
    end
  end
end

#target_path(path = nil) ⇒ Object



100
101
102
103
104
105
106
107
# File 'lib/jirametrics/exporter.rb', line 100

def target_path path = nil
  unless path.nil?
    @target_path = path
    @target_path += File::SEPARATOR unless @target_path.end_with? File::SEPARATOR
    FileUtils.mkdir_p @target_path
  end
  @target_path
end

#timezone_offset(offset = nil) ⇒ Object



114
115
116
117
# File 'lib/jirametrics/exporter.rb', line 114

def timezone_offset offset = nil
  @timezone_offset = offset unless offset.nil?
  @timezone_offset
end

#xproject(*args) ⇒ Object



98
# File 'lib/jirametrics/exporter.rb', line 98

def xproject *args; end