abt-cli 0.0.30 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
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"