harvest-time-off 0.2.0 → 0.3.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 +4 -4
- data/README.md +13 -1
- data/bin/harvest-work-entry +6 -0
- data/lib/harvest_time_off/version.rb +1 -1
- data/lib/harvest_time_off/work_entry_cli.rb +87 -0
- data/lib/harvest_time_off.rb +2 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 281fe13df87f06f4e9ffc0cd8cbd3df85e23f29400460dfbc0cca59182f8b641
|
|
4
|
+
data.tar.gz: 2512474000205216fb1ecabe4da817766a85ce4b5a6a088f7ec0c41be5dc51c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c0a91b9787d899a64ceb1186935c5e196d3c75a14b0a71a027209b225174088fea6fc1aa8f60a4ad2a4ec975a96994969e4495232d523d5b5aee899aff5456f
|
|
7
|
+
data.tar.gz: d7b776f47216657ec923475ab54cb0d4f34fa1c2ba35f06bf1b207b11f495490a713601a6912e02bd6c8ac4ab218cd84acea59c32e4a998a47f914714e3f71cd
|
data/README.md
CHANGED
|
@@ -38,10 +38,21 @@ A time-off block never creates weekend entries. The underlying [`marlens-harvest
|
|
|
38
38
|
- `defaultHours`: hours per business day when a tool call omits `hours`; defaults to `7`.
|
|
39
39
|
- `holidayRegions`: comma-separated Holidays regions; defaults to `ca_yt`.
|
|
40
40
|
- `command`: direct path to the `harvest-time-off` executable.
|
|
41
|
+
- `workEntryCommand`: direct path to the `harvest-work-entry` executable.
|
|
42
|
+
- `projectTimeMappings`: JSON mapping from OMP Project Time project names to Harvest project/task names.
|
|
43
|
+
- `projectTimeLogPath`: optional override for `~/.omp/project-time/time-log.json`.
|
|
41
44
|
|
|
42
45
|
## V2: OMP Project Time integration
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
Configure `projectTimeMappings` with the recorded OMP Project Time project name as the key:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"Harvest API": { "project": "Internal", "task": "Development" }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`harvest_preview_project_time_entries` reads the configured time log, splits sessions across local dates, generates descriptions from the project and repository, and checks Harvest for existing or locked entries without writing. `harvest_record_project_time_entries` performs the same preflight then creates only new entries; OMP treats it as a write requiring approval. Unmapped sessions are reported and never written.
|
|
45
56
|
|
|
46
57
|
## Release
|
|
47
58
|
|
|
@@ -60,4 +71,5 @@ gem push harvest-time-off-<version>.gem
|
|
|
60
71
|
omp plugin install --force github:klondikemarlen/harvest-time-off
|
|
61
72
|
omp plugin list
|
|
62
73
|
harvest-time-off --help
|
|
74
|
+
harvest-work-entry --help
|
|
63
75
|
```
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarvestTimeOff
|
|
4
|
+
class WorkEntryCLI
|
|
5
|
+
EXISTING_ENTRY = 2
|
|
6
|
+
LOCKED_ENTRY = 3
|
|
7
|
+
|
|
8
|
+
def self.run(arguments, output: $stdout, error: $stderr, client: nil)
|
|
9
|
+
options = { dry_run: false }
|
|
10
|
+
parser = option_parser(options)
|
|
11
|
+
dates = parser.parse(arguments)
|
|
12
|
+
validate!(dates, options)
|
|
13
|
+
|
|
14
|
+
spent_date = Date.iso8601(dates.first)
|
|
15
|
+
client ||= Marlens::HarvestApiV2::Client.from_environment
|
|
16
|
+
project_id, task_id = if options[:project_id]
|
|
17
|
+
[options[:project_id], options[:task_id]]
|
|
18
|
+
else
|
|
19
|
+
CLI.resolve_assignment(client, options[:project], options[:task])
|
|
20
|
+
end
|
|
21
|
+
existing_entries = client.request(
|
|
22
|
+
:get,
|
|
23
|
+
"/v2/time_entries",
|
|
24
|
+
params: { project_id:, task_id:, from: spent_date.iso8601, to: spent_date.iso8601 }
|
|
25
|
+
).fetch("time_entries")
|
|
26
|
+
|
|
27
|
+
if existing_entries.any? { |entry| entry["is_locked"] }
|
|
28
|
+
output.puts "Locked existing Harvest entry on #{spent_date.iso8601}; skipped"
|
|
29
|
+
return LOCKED_ENTRY
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if existing_entries.any?
|
|
33
|
+
output.puts "Existing Harvest entry on #{spent_date.iso8601}; skipped"
|
|
34
|
+
return EXISTING_ENTRY
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
if options[:dry_run]
|
|
38
|
+
output.puts "Would create #{spent_date.iso8601}: #{HarvestTimeOff.display_hours(options[:hours])}h on #{options[:project]} / #{options[:task]}; #{options[:notes]}"
|
|
39
|
+
return 0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
entry = client.create_time_entry(
|
|
43
|
+
project_id:,
|
|
44
|
+
task_id:,
|
|
45
|
+
spent_date:,
|
|
46
|
+
hours: options[:hours],
|
|
47
|
+
notes: options[:notes]
|
|
48
|
+
)
|
|
49
|
+
output.puts "Created #{spent_date.iso8601}: #{HarvestTimeOff.display_hours(options[:hours])}h (entry ##{entry.fetch("id")})"
|
|
50
|
+
0
|
|
51
|
+
rescue Error, Marlens::HarvestApiV2::Error, OptionParser::ParseError, Date::Error => e
|
|
52
|
+
error.puts "Error: #{e.message}"
|
|
53
|
+
error.puts parser if parser
|
|
54
|
+
1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.option_parser(options)
|
|
58
|
+
OptionParser.new do |opts|
|
|
59
|
+
opts.banner = "Usage: harvest-work-entry DATE --project NAME --task NAME --hours HOURS --notes NOTES [--dry-run]"
|
|
60
|
+
opts.on("--project NAME", "Harvest project name") { |value| options[:project] = value }
|
|
61
|
+
opts.on("--task NAME", "Harvest task name") { |value| options[:task] = value }
|
|
62
|
+
opts.on("--project-id ID", Integer, "Harvest project ID") { |value| options[:project_id] = value }
|
|
63
|
+
opts.on("--task-id ID", Integer, "Harvest task ID") { |value| options[:task_id] = value }
|
|
64
|
+
opts.on("--hours HOURS", Float, "Hours for this entry") { |value| options[:hours] = value }
|
|
65
|
+
opts.on("--notes NOTES", "Entry description") { |value| options[:notes] = value }
|
|
66
|
+
opts.on("--dry-run", "Check for existing entries without writing") { options[:dry_run] = true }
|
|
67
|
+
opts.on("-h", "--help", "Show this help") do
|
|
68
|
+
puts opts
|
|
69
|
+
exit 0
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.validate!(dates, options)
|
|
75
|
+
raise Error, "DATE is required" unless dates.length == 1
|
|
76
|
+
raise Error, "--hours must be a positive finite number" unless options[:hours]&.positive? && options[:hours].finite?
|
|
77
|
+
raise Error, "--notes is required" unless options[:notes] && !options[:notes].empty?
|
|
78
|
+
|
|
79
|
+
names_provided = options[:project] || options[:task]
|
|
80
|
+
ids_provided = options[:project_id] || options[:task_id]
|
|
81
|
+
valid_names = options[:project] && options[:task]
|
|
82
|
+
valid_ids = options[:project_id] && options[:task_id]
|
|
83
|
+
raise Error, "supply --project and --task, or --project-id and --task-id" unless valid_names || valid_ids
|
|
84
|
+
raise Error, "do not combine project/task names with IDs" if names_provided && ids_provided
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/harvest_time_off.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: harvest-time-off
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marlen Brunner
|
|
@@ -55,14 +55,17 @@ email:
|
|
|
55
55
|
- klondikemarlen@gmail.com
|
|
56
56
|
executables:
|
|
57
57
|
- harvest-time-off
|
|
58
|
+
- harvest-work-entry
|
|
58
59
|
extensions: []
|
|
59
60
|
extra_rdoc_files: []
|
|
60
61
|
files:
|
|
61
62
|
- README.md
|
|
62
63
|
- bin/harvest-time-off
|
|
64
|
+
- bin/harvest-work-entry
|
|
63
65
|
- harvest-time-off.rb
|
|
64
66
|
- lib/harvest_time_off.rb
|
|
65
67
|
- lib/harvest_time_off/version.rb
|
|
68
|
+
- lib/harvest_time_off/work_entry_cli.rb
|
|
66
69
|
homepage: https://github.com/klondikemarlen/harvest-time-off
|
|
67
70
|
licenses:
|
|
68
71
|
- MIT
|
|
@@ -84,5 +87,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
87
|
requirements: []
|
|
85
88
|
rubygems_version: 4.0.3
|
|
86
89
|
specification_version: 4
|
|
87
|
-
summary: Create Harvest time-off
|
|
90
|
+
summary: Create Harvest time-off and reviewed OMP Project Time entries.
|
|
88
91
|
test_files: []
|