tempest_time 0.6.2 → 0.7.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/.gitignore +2 -1
- data/lib/tempest_time/api/request.rb +3 -1
- data/lib/tempest_time/cli.rb +4 -0
- data/lib/tempest_time/commands/issue/list.rb +3 -3
- data/lib/tempest_time/commands/issue/open.rb +4 -4
- data/lib/tempest_time/commands/issue.rb +2 -2
- data/lib/tempest_time/commands/submit.rb +0 -1
- data/lib/tempest_time/commands/timer/delete.rb +33 -0
- data/lib/tempest_time/commands/timer/list.rb +59 -0
- data/lib/tempest_time/commands/timer/pause.rb +26 -0
- data/lib/tempest_time/commands/timer/start.rb +27 -0
- data/lib/tempest_time/commands/timer/status.rb +33 -0
- data/lib/tempest_time/commands/timer/track.rb +44 -0
- data/lib/tempest_time/commands/timer.rb +48 -0
- data/lib/tempest_time/commands/track.rb +2 -3
- data/lib/tempest_time/helpers/time_helper.rb +9 -0
- data/lib/tempest_time/models/report.rb +0 -1
- data/lib/tempest_time/models/timer.rb +81 -0
- data/lib/tempest_time/version.rb +3 -1
- metadata +9 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bee4c127b0d41d0f31cf49f9b3291c5948060eb44a8e9835720cb94ab9ffd123
|
4
|
+
data.tar.gz: 7d8102ca79d54c07b6ade649135f5a545d6a6e2297564420e1cd762b18980b4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6db29dd83c233f730e47f8226292f305ae8c99c8f640846f271314ab3365c59e0ebbed337910fbf7b28971ccde1e5e645b1f8b19ea0e3cdfd368a2c1b34ec0e2
|
7
|
+
data.tar.gz: c8d4feac6d657e579d0382e72331dd18a33b5a13e024c12baf67c7d7131c2acc6087e95ebceb53a0199cda97888e6e7976462bec2fd4c2992f70613b1c37c2cb
|
data/.gitignore
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'httparty'
|
2
4
|
require 'json'
|
3
5
|
|
@@ -9,7 +11,7 @@ module TempestTime
|
|
9
11
|
class Request
|
10
12
|
include HTTParty
|
11
13
|
|
12
|
-
DATE_FORMAT = "%Y-%m-%d"
|
14
|
+
DATE_FORMAT = "%Y-%m-%d"
|
13
15
|
|
14
16
|
def initialize(*args)
|
15
17
|
self.class.base_uri credentials.fetch(:url)
|
data/lib/tempest_time/cli.rb
CHANGED
@@ -81,6 +81,10 @@ module TempestTime
|
|
81
81
|
TempestTime::Commands::Track.new(time, issues, options).execute
|
82
82
|
end
|
83
83
|
|
84
|
+
require_relative 'commands/timer'
|
85
|
+
register TempestTime::Commands::Timer,
|
86
|
+
'timer', 'timer [SUBCOMMAND]', 'Start, Stop, Delete, Submit Timers'
|
87
|
+
|
84
88
|
map log: :track
|
85
89
|
end
|
86
90
|
end
|
@@ -25,14 +25,14 @@ module TempestTime
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def browser_prompt(issues)
|
28
|
-
abort if prompt.no?('Open
|
29
|
-
|
28
|
+
abort if prompt.no?('Open any issues in your browser?')
|
29
|
+
selections = prompt.multi_select(
|
30
30
|
'Select an issue to open in browser, or press ^C to quit.',
|
31
31
|
issues.map(&:key),
|
32
32
|
per_page: 5
|
33
33
|
)
|
34
34
|
require_relative 'open'
|
35
|
-
Open.new(
|
35
|
+
Open.new(selections).execute
|
36
36
|
end
|
37
37
|
|
38
38
|
def format_output(issues)
|
@@ -7,13 +7,13 @@ module TempestTime
|
|
7
7
|
module Commands
|
8
8
|
class Issue
|
9
9
|
class Open < TempestTime::Command
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
@
|
10
|
+
def initialize(issues)
|
11
|
+
@issues = issues.map(&:upcase)
|
12
|
+
@issues = [automatic_issue] if issues.empty?
|
13
13
|
end
|
14
14
|
|
15
15
|
def execute(input: $stdin, output: $stdout)
|
16
|
-
command.run("open #{url(
|
16
|
+
@issues.each { |issue| command.run("open #{url(issue)}") }
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
@@ -15,9 +15,9 @@ module TempestTime
|
|
15
15
|
end
|
16
16
|
|
17
17
|
desc 'open', 'Open an issue in your browser. (Default: current branch)'
|
18
|
-
def open(
|
18
|
+
def open(*issues)
|
19
19
|
require_relative 'issue/open'
|
20
|
-
TempestTime::Commands::Issue::Open.new(
|
20
|
+
TempestTime::Commands::Issue::Open.new(issues).execute
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../models/timer'
|
5
|
+
|
6
|
+
module TempestTime
|
7
|
+
module Commands
|
8
|
+
class Timer
|
9
|
+
class Delete < TempestTime::Command
|
10
|
+
def initialize(issue)
|
11
|
+
@issue = issue || automatic_issue
|
12
|
+
@timer = TempestTime::Models::Timer.new(@issue)
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(input: $stdin, output: $stdout)
|
16
|
+
timer.delete ? deleted_message : no_timer_message
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :issue, :timer
|
22
|
+
|
23
|
+
def deleted_message
|
24
|
+
prompt.say('baleeted')
|
25
|
+
end
|
26
|
+
|
27
|
+
def no_timer_message
|
28
|
+
prompt.say('noleeted')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './status'
|
4
|
+
require_relative '../../command'
|
5
|
+
require_relative '../../models/timer'
|
6
|
+
|
7
|
+
module TempestTime
|
8
|
+
module Commands
|
9
|
+
class Timer
|
10
|
+
class List < TempestTime::Command
|
11
|
+
def execute(input: $stdin, output: $stdout)
|
12
|
+
all_timers.each do |timer|
|
13
|
+
TempestTime::Commands::Timer::Status.new(timer.issue).execute
|
14
|
+
end
|
15
|
+
issue = prompt.select(
|
16
|
+
'Please select a timer to toggle / track, or enter ^C to exit.',
|
17
|
+
all_timers.map(&:issue)
|
18
|
+
)
|
19
|
+
action = action_prompt(timer(issue))
|
20
|
+
take_action(issue, action)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def all_timers
|
26
|
+
@all_timers ||= TempestTime::Models::Timer.all_timers
|
27
|
+
end
|
28
|
+
|
29
|
+
def timer(issue)
|
30
|
+
all_timers.detect { |timer| timer.issue == issue }
|
31
|
+
end
|
32
|
+
|
33
|
+
def action_prompt(timer)
|
34
|
+
if timer.running?
|
35
|
+
prompt.select('', %w[Pause Track])
|
36
|
+
else
|
37
|
+
prompt.select('', %w[Resume Track])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def take_action(issue, action)
|
42
|
+
case action
|
43
|
+
when 'Pause'
|
44
|
+
require_relative './pause'
|
45
|
+
TempestTime::Commands::Timer::Pause.new(issue).execute
|
46
|
+
when 'Resume'
|
47
|
+
require_relative './start'
|
48
|
+
TempestTime::Commands::Timer::Start.new(issue).execute
|
49
|
+
when 'Track'
|
50
|
+
require_relative './track'
|
51
|
+
TempestTime::Commands::Timer::Track.new(issue).execute
|
52
|
+
else
|
53
|
+
abort
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../models/timer'
|
5
|
+
|
6
|
+
module TempestTime
|
7
|
+
module Commands
|
8
|
+
class Timer
|
9
|
+
class Pause < TempestTime::Command
|
10
|
+
def initialize(issue)
|
11
|
+
@issue = issue || automatic_issue
|
12
|
+
@timer = TempestTime::Models::Timer.new(@issue)
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(input: $stdin, output: $stdout)
|
16
|
+
timer.pause
|
17
|
+
TempestTime::Commands::Timer::Status.new(issue).execute
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :issue, :timer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './status'
|
4
|
+
require_relative '../../command'
|
5
|
+
require_relative '../../models/timer'
|
6
|
+
|
7
|
+
module TempestTime
|
8
|
+
module Commands
|
9
|
+
class Timer
|
10
|
+
class Start < TempestTime::Command
|
11
|
+
def initialize(issue)
|
12
|
+
@issue = issue || automatic_issue
|
13
|
+
@timer = TempestTime::Models::Timer.new(@issue)
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(input: $stdin, output: $stdout)
|
17
|
+
timer.start
|
18
|
+
TempestTime::Commands::Timer::Status.new(issue).execute
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :issue, :timer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../models/timer'
|
5
|
+
|
6
|
+
module TempestTime
|
7
|
+
module Commands
|
8
|
+
class Timer
|
9
|
+
class Status < TempestTime::Command
|
10
|
+
def initialize(issue)
|
11
|
+
@issue = issue
|
12
|
+
@timer = TempestTime::Models::Timer.new(issue)
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(input: $stdin, output: $stdout)
|
16
|
+
prompt.say("#{issue}: #{status_message}")
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :issue, :timer
|
22
|
+
|
23
|
+
def status_message
|
24
|
+
if timer.running?
|
25
|
+
pastel.green("#{formatted_time_long(timer.runtime)} running")
|
26
|
+
else
|
27
|
+
pastel.yellow("#{formatted_time_long(timer.runtime)} paused")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../track'
|
4
|
+
require_relative '../../command'
|
5
|
+
require_relative '../../models/timer'
|
6
|
+
|
7
|
+
module TempestTime
|
8
|
+
module Commands
|
9
|
+
class Timer
|
10
|
+
class Track < TempestTime::Command
|
11
|
+
attr_reader :timer, :issue
|
12
|
+
|
13
|
+
def initialize(issue)
|
14
|
+
@issue = issue || automatic_issue
|
15
|
+
@timer = TempestTime::Models::Timer.new(@issue)
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(input: $stdin, output: $stdout)
|
19
|
+
abort(pastel.red("No timer for #{issue}!")) unless timer.exists?
|
20
|
+
timer.pause
|
21
|
+
track_time
|
22
|
+
timer.delete
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def track_time
|
28
|
+
time = prompt.ask(
|
29
|
+
"How much time should be logged to #{issue}?",
|
30
|
+
default: formatted_time_for_input(timer.runtime)
|
31
|
+
)
|
32
|
+
billable = prompt.yes?('Is this time billable?')
|
33
|
+
message = prompt.ask('Add a message. (optional)')
|
34
|
+
Commands::Track.new(
|
35
|
+
parsed_time(time),
|
36
|
+
[issue],
|
37
|
+
'message' => message,
|
38
|
+
'billable' => billable
|
39
|
+
).execute
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module TempestTime
|
6
|
+
module Commands
|
7
|
+
class Timer < Thor
|
8
|
+
|
9
|
+
namespace :timer
|
10
|
+
|
11
|
+
desc 'start [ISSUE]', 'Start a new timer, or continue a paused timer.'
|
12
|
+
def start(issue = nil)
|
13
|
+
require_relative 'timer/start'
|
14
|
+
TempestTime::Commands::Timer::Start.new(issue).execute
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'pause [ISSUE]', 'Pause a timer.'
|
18
|
+
def pause(issue = nil)
|
19
|
+
require_relative 'timer/pause'
|
20
|
+
TempestTime::Commands::Timer::Pause.new(issue).execute
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'track [ISSUE]', 'Stop and track a timer.'
|
24
|
+
def track(issue = nil)
|
25
|
+
require_relative 'timer/track'
|
26
|
+
TempestTime::Commands::Timer::Track.new(issue).execute
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'delete [ISSUE]', 'Delete current timer.'
|
30
|
+
def delete(issue = nil)
|
31
|
+
require_relative 'timer/delete'
|
32
|
+
TempestTime::Commands::Timer::Delete.new(issue).execute
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'status [ISSUE]', 'Display timer status.'
|
36
|
+
def status(issue = nil)
|
37
|
+
require_relative 'timer/status'
|
38
|
+
TempestTime::Commands::Timer::Status.new(issue).execute
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'list', 'Display all timers.'
|
42
|
+
def list
|
43
|
+
require_relative 'timer/list'
|
44
|
+
TempestTime::Commands::Timer::List.new.execute
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -2,9 +2,8 @@
|
|
2
2
|
|
3
3
|
require_relative '../command'
|
4
4
|
require_relative '../helpers/time_helper'
|
5
|
-
|
6
|
-
require_relative '../api/tempo_api/requests/create_worklog'
|
7
5
|
require_relative '../api/jira_api/requests/get_issue'
|
6
|
+
require_relative '../api/tempo_api/requests/create_worklog'
|
8
7
|
|
9
8
|
module TempestTime
|
10
9
|
module Commands
|
@@ -27,7 +26,7 @@ module TempestTime
|
|
27
26
|
end
|
28
27
|
|
29
28
|
issues.each do |issue|
|
30
|
-
track_time(time, @options.merge(issue
|
29
|
+
track_time(time, @options.merge('issue' => issue))
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
@@ -21,6 +21,15 @@ module TempestTime
|
|
21
21
|
"#{(seconds / 3600.to_f).round(2)} hours"
|
22
22
|
end
|
23
23
|
|
24
|
+
def formatted_time_for_input(seconds)
|
25
|
+
return "#{(seconds / 60).to_i}m" if seconds < 3600
|
26
|
+
"#{(seconds / 3600.to_f).round(2)}h"
|
27
|
+
end
|
28
|
+
|
29
|
+
def formatted_time_long(seconds)
|
30
|
+
Time.at(seconds).utc.strftime("%H:%M:%S")
|
31
|
+
end
|
32
|
+
|
24
33
|
def formatted_date_range(start_date, end_date)
|
25
34
|
return formatted_date(start_date) if end_date.nil?
|
26
35
|
"#{formatted_date(start_date)} - #{formatted_date(end_date)}"
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module TempestTime
|
6
|
+
module Models
|
7
|
+
class Timer
|
8
|
+
TEMP_DIR = '/tmp/timer/logs'
|
9
|
+
FILE_EXT = '.timer'
|
10
|
+
PREFIX_SEPARATOR = '___'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def all_timers
|
14
|
+
issues = Dir.glob("#{TEMP_DIR}/*#{FILE_EXT}").map do |file|
|
15
|
+
file.delete(TEMP_DIR).split(PREFIX_SEPARATOR).first
|
16
|
+
end
|
17
|
+
|
18
|
+
issues.uniq.sort.map { |issue| new(issue) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :issue
|
23
|
+
|
24
|
+
def initialize(issue)
|
25
|
+
ensure_tmp_dir
|
26
|
+
@issue = issue || automatic_issue
|
27
|
+
end
|
28
|
+
|
29
|
+
def start
|
30
|
+
return false if running?
|
31
|
+
Tempfile.create([log_file_prefix, FILE_EXT], TEMP_DIR)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pause
|
35
|
+
log_files.each do |log|
|
36
|
+
FileUtils.touch(log) if log_running?(log)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete
|
41
|
+
return false unless exists?
|
42
|
+
log_files.each { |log| File.unlink log }
|
43
|
+
end
|
44
|
+
|
45
|
+
def runtime
|
46
|
+
@logs ||= log_files.each_with_object([]) do |log, array|
|
47
|
+
start_time = File.birthtime(log)
|
48
|
+
end_time = log_running?(log) ? Time.now : File.mtime(log)
|
49
|
+
|
50
|
+
array << (end_time - start_time)
|
51
|
+
end.sum
|
52
|
+
end
|
53
|
+
|
54
|
+
def running?
|
55
|
+
log_files.any? { |log| log_running?(log) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def exists?
|
59
|
+
log_files.any?
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def log_file_prefix
|
65
|
+
"#{issue}#{PREFIX_SEPARATOR}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def log_running?(log)
|
69
|
+
File.birthtime(log).eql? File.mtime(log)
|
70
|
+
end
|
71
|
+
|
72
|
+
def log_files
|
73
|
+
@log_files ||= Dir.glob("#{TEMP_DIR}/#{issue}*#{FILE_EXT}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def ensure_tmp_dir
|
77
|
+
FileUtils.mkdir_p TEMP_DIR unless File.directory? TEMP_DIR
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/tempest_time/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tempest_time
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devan Hurst
|
@@ -463,11 +463,19 @@ files:
|
|
463
463
|
- lib/tempest_time/commands/teams/add.rb
|
464
464
|
- lib/tempest_time/commands/teams/delete.rb
|
465
465
|
- lib/tempest_time/commands/teams/edit.rb
|
466
|
+
- lib/tempest_time/commands/timer.rb
|
467
|
+
- lib/tempest_time/commands/timer/delete.rb
|
468
|
+
- lib/tempest_time/commands/timer/list.rb
|
469
|
+
- lib/tempest_time/commands/timer/pause.rb
|
470
|
+
- lib/tempest_time/commands/timer/start.rb
|
471
|
+
- lib/tempest_time/commands/timer/status.rb
|
472
|
+
- lib/tempest_time/commands/timer/track.rb
|
466
473
|
- lib/tempest_time/commands/track.rb
|
467
474
|
- lib/tempest_time/helpers/formatting_helper.rb
|
468
475
|
- lib/tempest_time/helpers/git_helper.rb
|
469
476
|
- lib/tempest_time/helpers/time_helper.rb
|
470
477
|
- lib/tempest_time/models/report.rb
|
478
|
+
- lib/tempest_time/models/timer.rb
|
471
479
|
- lib/tempest_time/setting.rb
|
472
480
|
- lib/tempest_time/settings/app.rb
|
473
481
|
- lib/tempest_time/settings/authorization.rb
|