Class: Exporter
- Defined in:
- lib/jirametrics/examples/standard_project.rb,
lib/jirametrics/exporter.rb,
lib/jirametrics/examples/aggregated_project.rb
Overview
This file is really intended to give you ideas about how you might configure your own reports, not as a complete setup that will work in every case.
The point of an AGGREGATED report is that we’re now looking at a higher level. We might use this in a S2 meeting (Scrum of Scrums) to talk about the things that are happening across teams, not within a single team. For that reason, we look at slightly different things that we would on a single team board.
Instance Attribute Summary collapse
-
#file_system ⇒ Object
Returns the value of attribute file_system.
-
#project_configs ⇒ Object
readonly
Returns the value of attribute project_configs.
Class Method Summary collapse
Instance Method Summary collapse
- #aggregated_project(name:, project_names:, settings: {}) ⇒ Object
- #download(name_filter:) ⇒ Object
- #downloading? ⇒ Boolean
- #each_project_config(name_filter:) ⇒ Object
- #export(name_filter:) ⇒ Object
- #holiday_dates(*args) ⇒ Object
- #info(keys, name_filter:) ⇒ Object
-
#initialize(file_system: FileSystem.new) ⇒ Exporter
constructor
A new instance of Exporter.
- #jira_config(filename = nil) ⇒ Object
- #project(name: nil, &block) ⇒ Object
- #standard_project(name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {}, default_board: nil, anonymize: false, settings: {}, status_category_mappings: {}, rolling_date_count: 90, no_earlier_than: nil, ignore_types: %w[Sub-task Subtask Epic],, show_experimental_charts: false) ⇒ Object
- #target_path(path = nil) ⇒ Object
- #timezone_offset(offset = nil) ⇒ Object
- #xproject(*args) ⇒ Object
Constructor Details
#initialize(file_system: FileSystem.new) ⇒ Exporter
Returns a new instance of Exporter.
36 37 38 39 40 41 42 43 44 |
# File 'lib/jirametrics/exporter.rb', line 36 def initialize file_system: FileSystem.new @project_configs = [] @target_path = '.' @holiday_dates = [] @downloading = false @file_system = file_system timezone_offset '+00:00' end |
Instance Attribute Details
#file_system ⇒ Object
Returns the value of attribute file_system.
19 20 21 |
# File 'lib/jirametrics/exporter.rb', line 19 def file_system @file_system end |
#project_configs ⇒ Object (readonly)
Returns the value of attribute project_configs.
18 19 20 |
# File 'lib/jirametrics/exporter.rb', line 18 def project_configs @project_configs end |
Class Method Details
.configure(&block) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/jirametrics/exporter.rb', line 21 def self.configure &block logfile_name = 'jirametrics.log' logfile = File.open logfile_name, 'w' file_system = FileSystem.new file_system.logfile = logfile file_system.logfile_name = logfile_name exporter = Exporter.new file_system: file_system exporter.instance_eval(&block) @@instance = exporter end |
.instance ⇒ Object
34 |
# File 'lib/jirametrics/exporter.rb', line 34 def self.instance = @@instance |
Instance Method Details
#aggregated_project(name:, project_names:, settings: {}) ⇒ Object
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 |
# File 'lib/jirametrics/examples/aggregated_project.rb', line 11 def aggregated_project name:, project_names:, settings: {} project name: name do puts name self.settings.merge! settings 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 html '<h1>Boards included in this report</h1><ul>', type: :header board_lines = [] included_projects.each do |project| project.all_boards.each_value do |board| board_lines << "<a href='#{project.file_prefix}.html'>#{board.name}</a> from project #{project.name}" end end board_lines.sort.each { |line| html "<li>#{line}</li>", type: :header } html '</ul>', type: :header cycletime_scatterplot do show_trend_lines # For an aggregated report we group by board rather than by type grouping_rules do |issue, rules| rules.label = issue.board.name end end # aging_work_in_progress_chart daily_wip_by_parent_chart do # When aggregating, the chart tends to need more vertical space canvas height: 400, width: 800 end aging_work_table do # In an aggregated report, we likely only care about items that are old so exclude anything # under 21 days. age_cutoff 21 end dependency_chart do header_text 'Dependencies across boards' description_text 'We are only showing dependencies across boards.' # By default, the issue doesn't show what board it's on and this is important for an # aggregated view chart = self issue_rules do |issue, rules| chart.default_issue_rules.call(issue, rules) rules.label = rules.label.split('<BR/>').insert(1, "Board: #{issue.board.name}").join('<BR/>') end link_rules do |link, rules| chart.default_link_rules.call(link, rules) # Because this is the aggregated view, let's hide any link that doesn't cross boards. rules.ignore if link.origin.board == link.other_issue.board end end end end end end |
#download(name_filter:) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/jirametrics/exporter.rb', line 53 def download name_filter: @downloading = true each_project_config(name_filter: name_filter) do |project| project.evaluate_next_level next if project.aggregated_project? unless project.download_config raise "Project #{project.name.inspect} is missing a download section in the config. " \ 'That is required in order to download' end project.download_config.run downloader = Downloader.new( download_config: project.download_config, file_system: file_system, jira_gateway: JiraGateway.new(file_system: file_system) ) downloader.run end puts "Full output from downloader in #{file_system.logfile_name}" end |
#downloading? ⇒ Boolean
106 107 108 |
# File 'lib/jirametrics/exporter.rb', line 106 def downloading? @downloading end |
#each_project_config(name_filter:) ⇒ Object
100 101 102 103 104 |
# File 'lib/jirametrics/exporter.rb', line 100 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
46 47 48 49 50 51 |
# File 'lib/jirametrics/exporter.rb', line 46 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
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/jirametrics/exporter.rb', line 142 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 |
#info(keys, name_filter:) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/jirametrics/exporter.rb', line 75 def info keys, name_filter: selected = [] each_project_config(name_filter: name_filter) do |project| project.evaluate_next_level # next if project.aggregated_project? project.run load_only: true project.board_configs.each do |board_config| board_config.run end project.issues.each do |issue| selected << [project, issue] if keys.include? issue.key end rescue => e # rubocop:disable Style/RescueStandardError # This happens when we're attempting to load an aggregated project because it hasn't been # properly initialized. Since we don't care about aggregated projects, we just ignore it. raise unless e..start_with? 'This is an aggregated project and issues should have been included' end selected.each do |project, issue| puts "\nProject #{project.name}" puts issue.dump end end |
#jira_config(filename = nil) ⇒ Object
129 130 131 132 133 134 135 |
# File 'lib/jirametrics/exporter.rb', line 129 def jira_config filename = nil if filename @jira_config = file_system.load_json(filename) @jira_config['url'] = $1 if @jira_config['url'] =~ /^(.+)\/+$/ end @jira_config end |
#project(name: nil, &block) ⇒ Object
110 111 112 113 114 115 116 |
# File 'lib/jirametrics/exporter.rb', line 110 def project name: nil, &block 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, anonymize: false, settings: {}, status_category_mappings: {}, rolling_date_count: 90, no_earlier_than: nil, ignore_types: %w[Sub-task Subtask Epic],, show_experimental_charts: false) ⇒ Object
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 |
# File 'lib/jirametrics/examples/standard_project.rb', line 6 def standard_project name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {}, default_board: nil, anonymize: false, settings: {}, status_category_mappings: {}, rolling_date_count: 90, no_earlier_than: nil, ignore_types: %w[Sub-task Subtask Epic], show_experimental_charts: false project name: name do puts name self.anonymize if anonymize self.settings.merge! settings status_category_mappings.each do |status, category| status_category_mapping status: status, category: category end file_prefix file_prefix download do self.rolling_date_count(rolling_date_count) if rolling_date_count self.no_earlier_than(no_earlier_than) if no_earlier_than 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) end end issues.reject! do |issue| ignore_types.include? issue.type end discard_changes_before status_becomes: (starting_status || :backlog) # rubocop:disable Style/RedundantParentheses file do file_suffix '.html' issues.reject! { |issue| ignore_issues.include? issue.key } if ignore_issues html_report do board_id default_board if default_board html "<H1>#{name}</H1>", type: :header boards.each_key do |id| board = find_board id html "<div><a href='#{board.url}'>#{id} #{board.name}</a> (#{board.board_type})</div>", type: :header end cycletime_scatterplot do show_trend_lines end cycletime_histogram 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_table daily_wip_by_age_chart daily_wip_by_blocked_stalled_chart daily_wip_by_parent_chart flow_efficiency_scatterplot if show_experimental_charts expedited_chart sprint_burndown estimate_accuracy_chart dependency_chart end end end end |
#target_path(path = nil) ⇒ Object
120 121 122 123 124 125 126 127 |
# File 'lib/jirametrics/exporter.rb', line 120 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
137 138 139 140 |
# File 'lib/jirametrics/exporter.rb', line 137 def timezone_offset offset = nil @timezone_offset = offset unless offset.nil? @timezone_offset end |
#xproject(*args) ⇒ Object
118 |
# File 'lib/jirametrics/exporter.rb', line 118 def xproject *args; end |