harvest-worklog 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ead4ee3da24a3522c5b5e09e694de573b4e10c2736b7e328377197efd349dcb
4
- data.tar.gz: 41cce9ae00a04e151fd68914ddbb3200ae8451c837f93e95a8bd5b601ea1fc27
3
+ metadata.gz: b50e3af9480bb1ed9d5a98d4e746b3476cf14b10b04ce90dfacaacafa872bd52
4
+ data.tar.gz: cf030243de7c163c4fb1287af66bf60f50669b55fed524c1e304ff00d1b0ab21
5
5
  SHA512:
6
- metadata.gz: 2e2592d645f2153fab30539d0ad0fd103b8008c0025950c9222298fc1e06abf4cbd759f3b1a6e4a8eeba5ecf985670d13b994d430b870144afdf825a0ea44018
7
- data.tar.gz: 11f9e301054fc944a9abf5a4509777cb9e6e538d3cd5be2fd50fc06b2a88feaf577b7ae22265ffe7d0a45972f5a7d25f58b99fb9ea36fd54b9eaee2edce0cd64
6
+ metadata.gz: a70c1b74ccc40f2641a5668830783e7b5f3f6773d0bec2fe825dd1591ac0d4ca79f5e057a5b75d6f36dd98a20d106210b153af4f8364929533aca6f420c5a3e8
7
+ data.tar.gz: 52e27558d3af81deb788fce38892e7cb7410907f4974ef553f6e2c3998385054ebb6415a88531ec3465e39f4d8fda9bf63a72bc93b5e63ed72ca277ca0d24e6a
data/README.md CHANGED
@@ -21,7 +21,9 @@ Personal Access Tokens are the intended Harvest authentication method for person
21
21
 
22
22
  ```text
23
23
  harvest-worklog time-off FROM TO --project NAME --task NAME [options]
24
+ harvest-worklog time-off FROM TO --project-id ID --task-id ID [options]
24
25
  harvest-worklog work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [options]
26
+ harvest-worklog work-entry DATE --project-id ID --task-id ID --hours HOURS --notes NOTES [options]
25
27
  harvest-worklog aggregate FROM TO [--project NAME] [--task NAME]
26
28
  harvest-worklog timesheet DATE --project NAME [--task NAME]
27
29
  ```
@@ -42,6 +44,8 @@ The default holiday region is `ca_yt`. Add `--holiday-region REGION` or set `HAR
42
44
 
43
45
  A time-off block never creates weekend entries. When names are supplied, it resolves them from your active personal Harvest assignments, so a Project Manager role is not required.
44
46
 
47
+ The `harvest_record_time_off` OMP tool accepts the same name pair or ID pair. Its optional `holidayRegions` array adds per-call regions to the configured defaults.
48
+
45
49
  ### Reviewed ordinary work
46
50
 
47
51
  The `work-entry` command checks for existing or locked entries for its project, task, and date before creating a new duration entry. Use `--dry-run` to complete that preflight without a write. OMP Project Time uses the same path.
@@ -66,9 +70,9 @@ The `timesheet` command reads the authenticated user's compact daily Harvest vie
66
70
  harvest-worklog timesheet today --project WRAP
67
71
  ```
68
72
 
69
- OMP exposes the same CLI-only path through `/harvest-worklog today WRAP` and the read-only `harvest_time_sheet` tool. The wrapper never calls Harvest directly. A later, separate feature may upload reviewed content through the Harvest API; keep that write path separate from this read-only formatter.
73
+ OMP exposes the same CLI-only path through `/harvest-worklog timesheet today --project WRAP` and the read-only `harvest_time_sheet` tool. The wrapper never calls Harvest directly. A later, separate feature may upload reviewed content through the Harvest API; keep that write path separate from this read-only formatter.
70
74
 
71
- Type `/harvest-worklog ` in OMP to discover the compact and explicit timesheet forms, relative date tokens, and context-valid `--project`/`--task` options. Completion keeps filter values as editable text, and the slash command delegates the selected timesheet argument vector to the CLI.
75
+ Type `/harvest-worklog ` in OMP to discover `timesheet`, then select `today`, `yesterday`, or an ISO date before the contextual `--project` and `--task` options. Completion keeps filter values as editable text, and the slash command delegates the selected timesheet argument vector to the CLI.
72
76
 
73
77
  ## OMP settings
74
78
 
@@ -8,7 +8,7 @@ module HarvestWorklog
8
8
  options = {}
9
9
  parser = option_parser(options)
10
10
  dates = parser.parse(arguments)
11
- validate!(dates)
11
+ validate!(dates, options)
12
12
 
13
13
  from = Date.iso8601(dates[0])
14
14
  to = Date.iso8601(dates[1])
@@ -36,8 +36,10 @@ module HarvestWorklog
36
36
  end
37
37
  end
38
38
 
39
- def self.validate!(dates)
39
+ def self.validate!(dates, options = {})
40
40
  raise Error, "FROM and TO are required" unless dates.length == 2
41
+ raise Error, "--project must not be blank" if options[:project]&.strip&.empty?
42
+ raise Error, "--task must not be blank" if options[:task]&.strip&.empty?
41
43
  end
42
44
 
43
45
  def self.fetch_entries(client, from:, to:, user_id: nil)
@@ -46,7 +46,8 @@ module HarvestWorklog
46
46
 
47
47
  def self.validate!(dates, options)
48
48
  raise Error, "DATE is required" unless dates.length == 1
49
- raise Error, "--project is required" unless options[:project] && !options[:project].empty?
49
+ raise Error, "--project is required" unless options[:project] && !options[:project].strip.empty?
50
+ raise Error, "--task must not be blank" if options[:task]&.strip&.empty?
50
51
  end
51
52
 
52
53
  def self.print_timesheet(output, entries, spent_date:, requested_project:)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HarvestWorklog
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
@@ -42,7 +42,9 @@ module HarvestWorklog
42
42
  end
43
43
 
44
44
  if options[:dry_run]
45
- output.puts "Would create #{spent_date.iso8601}: #{HarvestWorklog.display_hours(options[:hours])}h on #{options[:project]} / #{options[:task]}; #{options[:notes]}"
45
+ project = options[:project] || "project ##{options[:project_id]}"
46
+ task = options[:task] || "task ##{options[:task_id]}"
47
+ output.puts "Would create #{spent_date.iso8601}: #{HarvestWorklog.display_hours(options[:hours])}h on #{project} / #{task}; #{options[:notes]}"
46
48
  return 0
47
49
  end
48
50
 
@@ -63,7 +65,10 @@ module HarvestWorklog
63
65
 
64
66
  def self.option_parser(options)
65
67
  OptionParser.new do |opts|
66
- opts.banner = "Usage: harvest-worklog work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [--dry-run]"
68
+ opts.banner = <<~USAGE
69
+ Usage: harvest-worklog work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [options]
70
+ harvest-worklog work-entry DATE --project-id ID --task-id ID --hours HOURS --notes NOTES [options]
71
+ USAGE
67
72
  opts.on("--project NAME", "Harvest project name") { |value| options[:project] = value }
68
73
  opts.on("--task NAME", "Harvest task name") { |value| options[:task] = value }
69
74
  opts.on("--project-id ID", Integer, "Harvest project ID") { |value| options[:project_id] = value }
@@ -82,12 +87,12 @@ module HarvestWorklog
82
87
  def self.validate!(dates, options)
83
88
  raise Error, "DATE is required" unless dates.length == 1
84
89
  raise Error, "--hours must be a positive finite number" unless options[:hours]&.positive? && options[:hours].finite?
85
- raise Error, "--notes is required" unless options[:notes] && !options[:notes].empty?
90
+ raise Error, "--notes is required" unless options[:notes] && !options[:notes].strip.empty?
86
91
 
87
92
  names_provided = options[:project] || options[:task]
88
93
  ids_provided = options[:project_id] || options[:task_id]
89
- valid_names = options[:project] && options[:task]
90
- valid_ids = options[:project_id] && options[:task_id]
94
+ valid_names = options[:project] && !options[:project].strip.empty? && options[:task] && !options[:task].strip.empty?
95
+ valid_ids = options[:project_id]&.positive? && options[:task_id]&.positive?
91
96
  raise Error, "supply --project and --task, or --project-id and --task-id" unless valid_names || valid_ids
92
97
  raise Error, "do not combine project/task names with IDs" if names_provided && ids_provided
93
98
  end
@@ -52,7 +52,9 @@ module HarvestWorklog
52
52
  <<~USAGE
53
53
  Usage:
54
54
  harvest-worklog time-off FROM TO --project NAME --task NAME [options]
55
+ harvest-worklog time-off FROM TO --project-id ID --task-id ID [options]
55
56
  harvest-worklog work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [options]
57
+ harvest-worklog work-entry DATE --project-id ID --task-id ID --hours HOURS --notes NOTES [options]
56
58
  harvest-worklog aggregate FROM TO [--project NAME] [--task NAME]
57
59
  harvest-worklog timesheet DATE --project NAME [--task NAME]
58
60
 
@@ -70,6 +72,7 @@ module HarvestWorklog
70
72
  options = { hours: 7.0, dry_run: false, holiday_regions: holiday_regions_from_environment }
71
73
  parser = option_parser(options)
72
74
  dates = parser.parse(arguments)
75
+ normalize_holiday_regions!(options[:holiday_regions])
73
76
  validate!(dates, options)
74
77
 
75
78
  from = Date.iso8601(dates[0])
@@ -133,11 +136,12 @@ module HarvestWorklog
133
136
  raise Error, "FROM and TO are required" unless dates.length == 2
134
137
  raise Error, "--hours must be a positive finite number" unless options[:hours].positive? && options[:hours].finite?
135
138
  raise Error, "--holiday-region or HARVEST_HOLIDAY_REGIONS is required" if options[:holiday_regions].empty?
139
+ raise Error, "--notes must not be blank" if options[:notes]&.strip&.empty?
136
140
 
137
141
  names_provided = options[:project] || options[:task]
138
142
  ids_provided = options[:project_id] || options[:task_id]
139
- valid_names = options[:project] && options[:task]
140
- valid_ids = options[:project_id] && options[:task_id]
143
+ valid_names = options[:project] && !options[:project].strip.empty? && options[:task] && !options[:task].strip.empty?
144
+ valid_ids = options[:project_id]&.positive? && options[:task_id]&.positive?
141
145
  raise Error, "supply --project and --task, or --project-id and --task-id" unless valid_names || valid_ids
142
146
  raise Error, "do not combine project/task names with IDs" if names_provided && ids_provided
143
147
  end
@@ -146,6 +150,13 @@ module HarvestWorklog
146
150
  ENV.fetch("HARVEST_HOLIDAY_REGIONS", "ca_yt").split(",").map { |region| region.strip.downcase }.reject(&:empty?)
147
151
  end
148
152
 
153
+ def self.normalize_holiday_regions!(regions)
154
+ regions.map! { |region| region.strip.downcase }
155
+ regions.reject!(&:empty?)
156
+ regions.uniq!
157
+ regions
158
+ end
159
+
149
160
  def self.resolve_assignment(client, project_name, task_name)
150
161
  # ponytail: one 2,000-item page covers personal assignments; follow cursor pagination if that ceiling is exceeded.
151
162
  matches = client.active_personal_task_assignments.select do |assignment|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: harvest-worklog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marlen Brunner