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.
See github.com/mikebowler/jirametrics/wiki/Examples-folder for more details
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
readonly
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
-
#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: {}) ⇒ 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.
33 34 35 36 37 38 39 40 41 |
# File 'lib/jirametrics/exporter.rb', line 33 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 (readonly)
Returns the value of attribute file_system.
16 17 18 |
# File 'lib/jirametrics/exporter.rb', line 16 def file_system @file_system end |
#project_configs ⇒ Object (readonly)
Returns the value of attribute project_configs.
16 17 18 |
# File 'lib/jirametrics/exporter.rb', line 16 def project_configs @project_configs end |
Class Method Details
.configure(&block) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/jirametrics/exporter.rb', line 18 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
31 |
# File 'lib/jirametrics/exporter.rb', line 31 def self.instance = @@instance |
Instance Method Details
#aggregated_project(name:, project_names:, settings: {}) ⇒ Object
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 |
# File 'lib/jirametrics/examples/aggregated_project.rb', line 13 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.values.each 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 issue_rules do |issue, rules| key = issue.key key = "<S>#{key} </S> " if issue.status.category_name == 'Done' rules.label = "<#{key} [#{issue.type}]<BR/>#{issue.board.name}<BR/>#{word_wrap issue.summary}>" end link_rules do |link, rules| # By default, the dependency chart shows everything. Clean it up a bit. case link.name when 'Cloners' # We don't want to see any clone links at all. rules.ignore when 'Blocks' # For blocks, by default Jira will have links going both # ways and we want them only going one way. Also make the # link red. rules.merge_bidirectional keep: 'outward' rules.line_color = 'red' end # 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
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/jirametrics/exporter.rb', line 50 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
78 79 80 |
# File 'lib/jirametrics/exporter.rb', line 78 def downloading? @downloading end |
#each_project_config(name_filter:) ⇒ Object
72 73 74 75 76 |
# File 'lib/jirametrics/exporter.rb', line 72 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
43 44 45 46 47 48 |
# File 'lib/jirametrics/exporter.rb', line 43 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
111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/jirametrics/exporter.rb', line 111 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
101 102 103 104 |
# File 'lib/jirametrics/exporter.rb', line 101 def jira_config filename = nil @jira_config = file_system.load_json(filename) unless filename.nil? @jira_config end |
#project(name: nil, &block) ⇒ Object
82 83 84 85 86 87 88 |
# File 'lib/jirametrics/exporter.rb', line 82 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: {}) ⇒ Object
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 |
# File 'lib/jirametrics/examples/standard_project.rb', line 8 def standard_project name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {}, default_board: nil, anonymize: false, settings: {}, status_category_mappings: {} project name: name do puts name self.anonymize if anonymize settings['blocked_link_text'] = ['is blocked by'] 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 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>#{name}</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) # rubocop:disable Style/RedundantParentheses 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 expedited_chart sprint_burndown estimate_accuracy_chart 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 else # This is a link type that we don't recognize. Dump it to standard out to draw attention # to it. puts "name=#{link.name}, label=#{link.label}" end end end end end end end |
#target_path(path = nil) ⇒ Object
92 93 94 95 96 97 98 99 |
# File 'lib/jirametrics/exporter.rb', line 92 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
106 107 108 109 |
# File 'lib/jirametrics/exporter.rb', line 106 def timezone_offset offset = nil @timezone_offset = offset unless offset.nil? @timezone_offset end |
#xproject(*args) ⇒ Object
90 |
# File 'lib/jirametrics/exporter.rb', line 90 def xproject *args; end |