harvest-worklog 0.9.0 → 0.10.1
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 +4 -4
- data/README.md +8 -3
- data/lib/harvest_worklog/aggregate_cli.rb +4 -2
- data/lib/harvest_worklog/timesheet_cli.rb +2 -1
- data/lib/harvest_worklog/version.rb +1 -1
- data/lib/harvest_worklog/work_entry_cli.rb +10 -5
- data/lib/harvest_worklog.rb +13 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59f6ddf4acd09bb36f6f508719fccdd81db151107203367cd85deec4fb4bb6da
|
|
4
|
+
data.tar.gz: ebabb8af8524ca17fa2e1972582853eaaef6c721a62df4ad68671091cd63a65f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 637f2eebaad54a58e481b9b860f6af18af769fb573c0af55843e7197a6e02101b4b8aeea998f99a0a2b81bde1d4606c0725715bcf676d51fabe9a025b58fb688
|
|
7
|
+
data.tar.gz: 2ce2096247b4b779a6e88615748d9df27c67841ffaf2dc6f8d70874deaa8ceafc8e7f4ff84f196bb970863932f2ad8eb5c97b314c5564667a068ae93119f0a1c
|
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.
|
|
@@ -60,15 +64,16 @@ The `harvest_time_aggregates` OMP tool exposes the same optional filters and is
|
|
|
60
64
|
|
|
61
65
|
### Daily timesheets
|
|
62
66
|
|
|
63
|
-
The `timesheet` command
|
|
67
|
+
The CLI `timesheet` command and `harvest_time_sheet` OMP tool read the authenticated user's compact daily Harvest view. They show task totals, entry durations, and notes already recorded in Harvest.
|
|
64
68
|
|
|
65
69
|
```bash
|
|
66
70
|
harvest-worklog timesheet today --project WRAP
|
|
67
71
|
```
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
The `/harvest-worklog timesheet today --project wrap` slash command instead reads local OMP Project Time and reports separate `Human active` and `Agent elapsed` totals. It does not call Harvest or require `projectTimeMappings`; mappings remain specific to previewing or recording Harvest entries.
|
|
74
|
+
`/project-time history` reports all logged dates, so its totals can be larger than a single-day timesheet.
|
|
70
75
|
|
|
71
|
-
Type `/harvest-worklog ` in OMP to discover
|
|
76
|
+
Type `/harvest-worklog ` in OMP to discover `timesheet`, then select `today`, `yesterday`, or an ISO date before the contextual `--project` option. The editable project name must exactly match the case-sensitive local Project Time name.
|
|
72
77
|
|
|
73
78
|
## OMP settings
|
|
74
79
|
|
|
@@ -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:)
|
|
@@ -42,7 +42,9 @@ module HarvestWorklog
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
if options[:dry_run]
|
|
45
|
-
|
|
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 =
|
|
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
|
data/lib/harvest_worklog.rb
CHANGED
|
@@ -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|
|