Class: HarvestWorklog::TimesheetCLI

Inherits:
Object
  • Object
show all
Defined in:
lib/harvest_worklog/timesheet_cli.rb

Class Method Summary collapse

Class Method Details

.current_user_id(client) ⇒ Object



43
44
45
# File 'lib/harvest_worklog/timesheet_cli.rb', line 43

def self.current_user_id(client)
  client.request(:get, "/v2/users/me", params: {}).fetch("id")
end

.option_parser(options) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/harvest_worklog/timesheet_cli.rb', line 23

def self.option_parser(options)
  OptionParser.new do |opts|
    opts.banner = "Usage: harvest-worklog timesheet DATE --project NAME [--task NAME]"
    opts.on("--project NAME", "Filter by Harvest project name") { |value| options[:project] = value }
    opts.on("--task NAME", "Filter by Harvest task name") { |value| options[:task] = value }
    opts.on("-h", "--help", "Show this help") do
      puts opts
      exit 0
    end
  end
end


76
77
78
79
80
# File 'lib/harvest_worklog/timesheet_cli.rb', line 76

def self.print_notes(output, notes, indent:)
  lines = notes.lines(chomp: true).reject(&:empty?)
  lines = ["(no notes)"] if lines.empty?
  lines.each { |line| output.puts "#{" " * indent}#{line}" }
end


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/harvest_worklog/timesheet_cli.rb', line 53

def self.print_timesheet(output, entries, spent_date:, requested_project:)
  project = entries.first&.dig("project", "name") || requested_project
  output.puts "#{project} · #{spent_date.strftime("%a, %b %-d")} · #{HarvestWorklog.display_hours(AggregateCLI.total_hours(entries))}h"
  if entries.empty?
    output.puts
    output.puts "No time entries."
    return
  end

  entries.group_by { |entry| entry.dig("task", "name") }.sort_by { |task, _| task.downcase }.each do |task, task_entries|
    output.puts
    output.puts "#{task} · #{HarvestWorklog.display_hours(AggregateCLI.total_hours(task_entries))}h"
    if task_entries.one?
      print_notes(output, task_entries.first["notes"].to_s, indent: 2)
    else
      task_entries.each do |entry|
        output.puts "  #{HarvestWorklog.display_hours(Float(entry.fetch("hours")))}h"
        print_notes(output, entry["notes"].to_s, indent: 4)
      end
    end
  end
end

.resolve_date(value, today: Date.today) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/harvest_worklog/timesheet_cli.rb', line 35

def self.resolve_date(value, today: Date.today)
  case value.downcase
  when "today" then today
  when "yesterday" then today - 1
  else Date.iso8601(value)
  end
end

.run(arguments, output: $stdout, error: $stderr, client: nil, today: Date.today) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/harvest_worklog/timesheet_cli.rb', line 5

def self.run(arguments, output: $stdout, error: $stderr, client: nil, today: Date.today)
  options = {}
  parser = option_parser(options)
  dates = parser.parse(arguments)
  validate!(dates, options)

  spent_date = resolve_date(dates.first, today:)
  client ||= Marlens::HarvestApiV2::Client.from_environment
  user_id = current_user_id(client)
  entries = AggregateCLI.fetch_entries(client, from: spent_date, to: spent_date, user_id:).select { |entry| AggregateCLI.matches?(entry, options) }
  print_timesheet(output, entries, spent_date:, requested_project: options[:project])
  0
rescue Error, Marlens::HarvestApiV2::Error, OptionParser::ParseError, Date::Error => e
  error.puts "Error: #{e.message}"
  error.puts parser if parser
  1
end

.validate!(dates, options) ⇒ Object

Raises:



47
48
49
50
51
# File 'lib/harvest_worklog/timesheet_cli.rb', line 47

def self.validate!(dates, options)
  raise Error, "DATE is required" unless dates.length == 1
  raise Error, "--project is required" unless options[:project] && !options[:project].strip.empty?
  raise Error, "--task must not be blank" if options[:task]&.strip&.empty?
end