Class: HarvestWorklog::AggregateCLI
- Inherits:
-
Object
- Object
- HarvestWorklog::AggregateCLI
- Defined in:
- lib/harvest_worklog/aggregate_cli.rb
Constant Summary collapse
- PER_PAGE =
100
Class Method Summary collapse
- .entry_label(count) ⇒ Object
- .fetch_entries(client, from:, to:) ⇒ Object
- .matches?(entry, options) ⇒ Boolean
- .name_matches?(actual, expected) ⇒ Boolean
- .option_parser(options) ⇒ Object
- .print_summary(output, entries, from:, to:) ⇒ Object
- .run(arguments, output: $stdout, error: $stderr, client: nil) ⇒ Object
- .total_hours(entries) ⇒ Object
- .validate!(dates) ⇒ Object
Class Method Details
.entry_label(count) ⇒ Object
93 94 95 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 93 def self.entry_label(count) count == 1 ? "entry" : "entries" end |
.fetch_entries(client, from:, to:) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 43 def self.fetch_entries(client, from:, to:) entries = [] page = 1 loop do response = client.request( :get, "/v2/time_entries", params: { from: from.iso8601, to: to.iso8601, page:, per_page: PER_PAGE } ) entries.concat(response.fetch("time_entries")) page = response["next_page"] break if page.nil? end entries end |
.matches?(entry, options) ⇒ Boolean
59 60 61 62 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 59 def self.matches?(entry, ) name_matches?(entry.dig("project", "name"), [:project]) && name_matches?(entry.dig("task", "name"), [:task]) end |
.name_matches?(actual, expected) ⇒ Boolean
64 65 66 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 64 def self.name_matches?(actual, expected) expected.nil? || actual&.casecmp?(expected) end |
.option_parser(options) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 27 def self.option_parser() OptionParser.new do |opts| opts. = "Usage: harvest-worklog aggregate FROM TO [--project NAME] [--task NAME]" opts.on("--project NAME", "Filter by Harvest project name") { |value| [:project] = value } opts.on("--task NAME", "Filter by Harvest task name") { |value| [:task] = value } opts.on("-h", "--help", "Show this help") do puts opts exit 0 end end end |
.print_summary(output, entries, from:, to:) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 68 def self.print_summary(output, entries, from:, to:) output.puts "#{entries.length} #{entry_label(entries.length)}, #{HarvestWorklog.display_hours(total_hours(entries))}h from #{from.iso8601} through #{to.iso8601}" output.puts "By date:" (from..to).each do |date| date_entries = entries.select { |entry| entry.fetch("spent_date") == date.iso8601 } output.puts " #{date.iso8601}: #{date_entries.length} #{entry_label(date_entries.length)}, #{HarvestWorklog.display_hours(total_hours(date_entries))}h" end output.puts "By project/task:" groups = entries.group_by { |entry| [entry.dig("project", "name"), entry.dig("task", "name")] } if groups.empty? output.puts " none" return end groups.keys.sort_by { |project, task| [project.downcase, task.downcase] }.each do |project, task| group = groups.fetch([project, task]) output.puts " #{project} / #{task}: #{group.length} #{entry_label(group.length)}, #{HarvestWorklog.display_hours(total_hours(group))}h" end end |
.run(arguments, output: $stdout, error: $stderr, client: nil) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 7 def self.run(arguments, output: $stdout, error: $stderr, client: nil) = {} parser = option_parser() dates = parser.parse(arguments) validate!(dates) from = Date.iso8601(dates[0]) to = Date.iso8601(dates[1]) raise Error, "end date must not be before start date" if to < from client ||= Marlens::HarvestApiV2::Client.from_environment entries = fetch_entries(client, from:, to:).select { |entry| matches?(entry, ) } print_summary(output, entries, from:, to:) 0 rescue Error, Marlens::HarvestApiV2::Error, OptionParser::ParseError, Date::Error => e error.puts "Error: #{e.}" error.puts parser if parser 1 end |
.total_hours(entries) ⇒ Object
89 90 91 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 89 def self.total_hours(entries) entries.sum { |entry| Float(entry.fetch("hours")) } end |
.validate!(dates) ⇒ Object
39 40 41 |
# File 'lib/harvest_worklog/aggregate_cli.rb', line 39 def self.validate!(dates) raise Error, "FROM and TO are required" unless dates.length == 2 end |