Class: HarvestWorklog::WorkEntryCLI
- Inherits:
-
Object
- Object
- HarvestWorklog::WorkEntryCLI
- Defined in:
- lib/harvest_worklog/work_entry_cli.rb
Constant Summary collapse
- EXISTING_ENTRY =
2- LOCKED_ENTRY =
3
Class Method Summary collapse
- .option_parser(options) ⇒ Object
- .run(arguments, output: $stdout, error: $stderr, client: nil) ⇒ Object
- .validate!(dates, options) ⇒ Object
Class Method Details
.option_parser(options) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/harvest_worklog/work_entry_cli.rb', line 66 def self.option_parser() OptionParser.new do |opts| opts. = <<~USAGE Usage: harvest-worklog work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [options] harvest-worklog work-entry DATE --project-id ID --task-id ID --hours HOURS --notes NOTES [options] USAGE opts.on("--project NAME", "Harvest project name") { |value| [:project] = value } opts.on("--task NAME", "Harvest task name") { |value| [:task] = value } opts.on("--project-id ID", Integer, "Harvest project ID") { |value| [:project_id] = value } opts.on("--task-id ID", Integer, "Harvest task ID") { |value| [:task_id] = value } opts.on("--hours HOURS", Float, "Hours for this entry") { |value| [:hours] = value } opts.on("--notes NOTES", "Entry description") { |value| [:notes] = value } opts.on("--dry-run", "Check for existing entries without writing") { [:dry_run] = true } opts.on("--activity-entry", "Allow distinct OMP Project Time activity entries on the same date, project, and task") { [:activity_entry] = true } opts.on("-h", "--help", "Show this help") do puts opts exit 0 end end end |
.run(arguments, output: $stdout, error: $stderr, client: nil) ⇒ 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 |
# File 'lib/harvest_worklog/work_entry_cli.rb', line 8 def self.run(arguments, output: $stdout, error: $stderr, client: nil) = { dry_run: false, activity_entry: false } parser = option_parser() dates = parser.parse(arguments) validate!(dates, ) spent_date = Date.iso8601(dates.first) client ||= Marlens::HarvestApiV2::Client.from_environment project_id, task_id = if [:project_id] [[:project_id], [:task_id]] else TimeOffCLI.resolve_assignment(client, [:project], [:task]) end existing_entries = client.request( :get, "/v2/time_entries", params: { project_id:, task_id:, from: spent_date.iso8601, to: spent_date.iso8601 } ).fetch("time_entries") if existing_entries.any? { |entry| entry["is_locked"] } output.puts "Locked existing Harvest entry on #{spent_date.iso8601}; skipped" return LOCKED_ENTRY end if [:activity_entry] activity_key = [:notes].lines.first = existing_entries.reject { |entry| entry["notes"]&.lines&.first&.start_with?("OMP Project Time activity: ") } if .any? || existing_entries.any? { |entry| entry["notes"]&.lines&.first == activity_key } output.puts "Existing Harvest entry on #{spent_date.iso8601}; skipped" return EXISTING_ENTRY end elsif existing_entries.any? output.puts "Existing Harvest entry on #{spent_date.iso8601}; skipped" return EXISTING_ENTRY end if [:dry_run] project = [:project] || "project ##{[:project_id]}" task = [:task] || "task ##{[:task_id]}" output.puts "Would create #{spent_date.iso8601}: #{HarvestWorklog.display_hours([:hours])}h on #{project} / #{task}; #{[:notes]}" return 0 end entry = client.create_time_entry( project_id:, task_id:, spent_date:, hours: [:hours], notes: [:notes] ) output.puts "Created #{spent_date.iso8601}: #{HarvestWorklog.display_hours([:hours])}h (entry ##{entry.fetch("id")})" 0 rescue Error, Marlens::HarvestApiV2::Error, OptionParser::ParseError, Date::Error => e error.puts "Error: #{e.}" error.puts parser if parser 1 end |
.validate!(dates, options) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/harvest_worklog/work_entry_cli.rb', line 87 def self.validate!(dates, ) raise Error, "DATE is required" unless dates.length == 1 raise Error, "--hours must be a positive finite number" unless [:hours]&.positive? && [:hours].finite? raise Error, "--notes is required" unless [:notes] && ![:notes].strip.empty? names_provided = [:project] || [:task] ids_provided = [:project_id] || [:task_id] valid_names = [:project] && ![:project].strip.empty? && [:task] && ![:task].strip.empty? valid_ids = [:project_id]&.positive? && [:task_id]&.positive? raise Error, "supply --project and --task, or --project-id and --task-id" unless valid_names || valid_ids raise Error, "do not combine project/task names with IDs" if names_provided && ids_provided end |