abt-cli 0.0.30 → 0.0.31

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: 7f0389f2300f5dc3f3143f6672d770a7dc50cce27b77774915eba3873cdfc89c
4
- data.tar.gz: bc7952525895e85a0b2d0b0e679ebf98a687647e86bf2b4250d9dcb0abc1e4ac
3
+ metadata.gz: 9b0f6705f90f844f11a301d2aee417ded8524de882bba8cd114d62ceee77ee92
4
+ data.tar.gz: d51120f9529853801fefd8b557102e1cac058685da5208f5a42577726e3c871d
5
5
  SHA512:
6
- metadata.gz: 484a395a41009899bb56e42049f0acb33e764ff8b4f54fbabdb5e7a468e663717f537a9b6e29934b02e6d668b7b6f3218fca35f6de3983ff32dd3e51a48ba7b3
7
- data.tar.gz: 0d1651b94be6bbc6c93fb68fee3b1ca2dab62aa5160994b29b0009ee68f77090c3303b145cb3aae49305c5742ace9153a7392c637c566422cdec088923de61df
6
+ metadata.gz: f2e08dd8e61a8d0271661af7e653b4da5d26f5ba0790cf657e2ec0c8524d784af707e1cd9bb2914192ba6943ae1d39f845aedd80c3dbffc2f529a46b9a0dba5d
7
+ data.tar.gz: 728e3b2cfbe503ab9188b789510c112e3f2c569e32a3a541f1f30e454bfdd80381f0a35185fc0b10ad9ff9751141dc168bdb84422b09657b46621f04df982df1
@@ -22,7 +22,7 @@ module Abt
22
22
  end
23
23
 
24
24
  def perform
25
- abort("Flags --global and --all cannot be used at the same time") if flags[:global] && flags[:all]
25
+ abort("Flags --global and --all cannot be used together") if flags[:global] && flags[:all]
26
26
 
27
27
  config.clear_local unless flags[:global]
28
28
  config.clear_global if flags[:global] || flags[:all]
@@ -22,7 +22,7 @@ module Abt
22
22
  end
23
23
 
24
24
  def perform
25
- abort("Flags --global and --all cannot be used at the same time") if flags[:global] && flags[:all]
25
+ abort("Flags --global and --all cannot be used together") if flags[:global] && flags[:all]
26
26
 
27
27
  config.clear_local unless flags[:global]
28
28
  config.clear_global if flags[:global] || flags[:all]
@@ -22,7 +22,7 @@ module Abt
22
22
  end
23
23
 
24
24
  def perform
25
- abort("Flags --global and --all cannot be used at the same time") if flags[:global] && flags[:all]
25
+ abort("Flags --global and --all cannot be used together") if flags[:global] && flags[:all]
26
26
 
27
27
  config.clear_local unless flags[:global]
28
28
  config.clear_global if flags[:global] || flags[:all]
@@ -4,7 +4,7 @@ module Abt
4
4
  module Providers
5
5
  module Harvest
6
6
  module Commands
7
- class Track < BaseCommand
7
+ class Track < BaseCommand # rubocop:disable Metrics/ClassLength
8
8
  def self.usage
9
9
  "abt track harvest[:<project-id>/<task-id>] [options]"
10
10
  end
@@ -20,15 +20,21 @@ module Abt
20
20
  ["-s", "--set", "Set specified task as current"],
21
21
  ["-c", "--comment COMMENT", "Override comment"],
22
22
  ["-t", "--time HOURS",
23
- "Set hours. Creates a stopped entry unless used with --running"],
24
- ["-r", "--running", "Used with --time, starts the created time entry"]
23
+ "Track amount of hours, this will create a stopped entry."],
24
+ ["-i", "--since HH:MM",
25
+ "Start entry today at specified time. The computed duration will be deducted from the running entry if one exists."] # rubocop:disable Layout/LineLength
25
26
  ]
26
27
  end
27
28
 
28
29
  def perform
30
+ abort("Flags --time and --since cannot be used together") if flags[:time] && flags[:since]
31
+
29
32
  require_task!
30
33
 
31
- print_task(created_time_entry["project"], created_time_entry["task"])
34
+ maybe_adjust_previous_entry
35
+ entry = create_entry!
36
+
37
+ print_task(entry["project"], entry["task"])
32
38
 
33
39
  maybe_override_current_task
34
40
  rescue Abt::HttpError::HttpError => _e
@@ -37,31 +43,41 @@ module Abt
37
43
 
38
44
  private
39
45
 
40
- def created_time_entry
41
- @created_time_entry ||= create_time_entry
46
+ def create_entry!
47
+ result = api.post("time_entries", Oj.dump(entry_data, mode: :json))
48
+ api.patch("time_entries/#{result['id']}/restart") if flags.key?(:since)
49
+ result
42
50
  end
43
51
 
44
- def create_time_entry
45
- body = time_entry_data
52
+ def maybe_adjust_previous_entry
53
+ return unless flags.key?(:since)
54
+ return unless since_flag_duration # Ensure --since flag is valid before fetching data
55
+ return unless previous_entry
56
+
57
+ adjust_previous_entry
58
+ end
46
59
 
47
- result = api.post("time_entries", Oj.dump(body, mode: :json))
60
+ def adjust_previous_entry
61
+ updated_hours = previous_entry["hours"] - since_flag_duration
62
+ abort("Cannot adjust previous entry to a negative duration") if updated_hours <= 0
48
63
 
49
- api.patch("time_entries/#{result['id']}/restart") if flags.key?(:time) && flags[:running]
64
+ api.patch("time_entries/#{previous_entry['id']}", Oj.dump({ hours: updated_hours }, mode: :json))
50
65
 
51
- result
66
+ subtracted_minutes = (since_flag_duration * 60).round
67
+ warn("~#{subtracted_minutes} minute(s) subtracted from previous entry")
52
68
  end
53
69
 
54
- def time_entry_data
55
- body = time_entry_base_data
70
+ def entry_data
71
+ body = entry_base_data
56
72
 
57
73
  maybe_add_external_link(body)
58
74
  maybe_add_comment(body)
59
- maybe_add_time(body)
75
+ maybe_add_hours(body)
60
76
 
61
77
  body
62
78
  end
63
79
 
64
- def time_entry_base_data
80
+ def entry_base_data
65
81
  {
66
82
  project_id: project_id,
67
83
  task_id: task_id,
@@ -74,8 +90,8 @@ module Abt
74
90
  if external_link_data
75
91
  warn(<<~TXT)
76
92
  Linking to:
77
- #{external_link_data[:notes]}
78
- #{external_link_data[:external_reference][:permalink]}
93
+ #{external_link_data[:notes]}
94
+ #{external_link_data[:external_reference][:permalink]}
79
95
  TXT
80
96
  body.merge!(external_link_data)
81
97
  else
@@ -83,38 +99,40 @@ module Abt
83
99
  end
84
100
  end
85
101
 
86
- def maybe_add_comment(body)
87
- body[:notes] = flags[:comment] if flags.key?(:comment)
88
- body[:notes] ||= cli.prompt.text("Fill in comment (optional)")
89
- end
90
-
91
- def maybe_add_time(body)
92
- body[:hours] = flags[:time] if flags.key?(:time)
93
- end
94
-
95
102
  def external_link_data
96
103
  return @external_link_data if instance_variable_defined?(:@external_link_data)
104
+ return @external_link_data = nil if link_data_lines.empty?
97
105
 
98
- lines = fetch_link_data_lines
99
-
100
- return @external_link_data = nil if lines.empty?
101
-
102
- if lines.length > 1
106
+ if link_data_lines.length > 1
103
107
  abort("Got reference data from multiple scheme providers, only one is supported at a time")
104
108
  end
105
109
 
106
- @external_link_data = Oj.load(lines.first, symbol_keys: true)
110
+ @external_link_data = Oj.load(link_data_lines.first, symbol_keys: true)
107
111
  end
108
112
 
109
- def fetch_link_data_lines
110
- other_aris = cli.aris - [ari]
111
- return [] if other_aris.empty?
113
+ def link_data_lines
114
+ @link_data_lines ||= begin
115
+ other_aris = cli.aris - [ari]
116
+ other_aris.map do |other_ari|
117
+ input = StringIO.new(other_ari.to_s)
118
+ output = StringIO.new
119
+ Abt::Cli.new(argv: ["harvest-time-entry-data"], output: output, input: input).perform
120
+ output.string.chomp
121
+ end.reject(&:empty?)
122
+ end
123
+ end
112
124
 
113
- input = StringIO.new(other_aris.to_s)
114
- output = StringIO.new
115
- Abt::Cli.new(argv: ["harvest-time-entry-data"], output: output, input: input).perform
125
+ def maybe_add_comment(body)
126
+ body[:notes] = flags[:comment] if flags.key?(:comment)
127
+ body[:notes] ||= cli.prompt.text("Fill in comment (optional)")
128
+ end
116
129
 
117
- output.string.strip.lines
130
+ def maybe_add_hours(body)
131
+ if flags[:time]
132
+ body[:hours] = flags[:time]
133
+ elsif flags[:since]
134
+ body[:hours] = since_flag_duration
135
+ end
118
136
  end
119
137
 
120
138
  def maybe_override_current_task
@@ -125,6 +143,21 @@ module Abt
125
143
  config.path = path
126
144
  warn("Current task updated")
127
145
  end
146
+
147
+ def since_flag_duration
148
+ @since_flag_duration ||= begin
149
+ since_hours = HarvestHelpers.decimal_hours_from_string(flags[:since])
150
+ now_hours = HarvestHelpers.decimal_hours_from_string(Time.now.strftime("%T"))
151
+
152
+ abort("Specified \"since\" time (#{flags[:since]}) is in the future") if now_hours <= since_hours
153
+
154
+ now_hours - since_hours
155
+ end
156
+ end
157
+
158
+ def previous_entry
159
+ @previous_entry ||= api.get_paged("time_entries", is_running: true, user_id: config.user_id).first
160
+ end
128
161
  end
129
162
  end
130
163
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ class HarvestHelpers
7
+ class << self
8
+ HOURS_REGEX = /(?<hours>\d+)/.freeze
9
+ MINUTES_REGEX = /(?<minutes>[0-5][0-9])/.freeze
10
+ SECONDS_REGEX = /(?<seconds>[0-5][0-9])/.freeze
11
+ TIME_REGEX = /^#{HOURS_REGEX}:#{MINUTES_REGEX}(?::#{SECONDS_REGEX})?$/.freeze
12
+
13
+ def decimal_hours_from_string(hh_mm_ss)
14
+ match = TIME_REGEX.match(hh_mm_ss)
15
+ raise Abt::Cli::Abort, "Invalid time: #{hh_mm_ss}, supported formats are: HH:MM, HH:MM:SS" if match.nil?
16
+
17
+ match[:hours].to_i +
18
+ match[:minutes].to_i / 60.0 +
19
+ match[:seconds].to_i / 60.0 / 60.0
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/abt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abt
4
- VERSION = "0.0.30"
4
+ VERSION = "0.0.31"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abt-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.30
4
+ version: 0.0.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesper Sørensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-31 00:00:00.000000000 Z
11
+ date: 2021-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-inflector
@@ -147,6 +147,7 @@ files:
147
147
  - "./lib/abt/providers/harvest/commands/track.rb"
148
148
  - "./lib/abt/providers/harvest/commands/write_config.rb"
149
149
  - "./lib/abt/providers/harvest/configuration.rb"
150
+ - "./lib/abt/providers/harvest/harvest_helpers.rb"
150
151
  - "./lib/abt/providers/harvest/path.rb"
151
152
  - "./lib/abt/providers/harvest/services/project_picker.rb"
152
153
  - "./lib/abt/providers/harvest/services/task_picker.rb"