tempest_time 0.5.2 → 0.5.3
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/Gemfile.lock +1 -1
- data/lib/tempest_time/api/tempo_api/requests/submit_timesheet.rb +3 -4
- data/lib/tempest_time/api/tempo_api/responses/list_worklogs.rb +1 -13
- data/lib/tempest_time/cli.rb +4 -10
- data/lib/tempest_time/command.rb +24 -0
- data/lib/tempest_time/commands/issues.rb +1 -1
- data/lib/tempest_time/commands/list.rb +38 -10
- data/lib/tempest_time/commands/report.rb +62 -31
- data/lib/tempest_time/commands/submit.rb +2 -14
- data/lib/tempest_time/commands/teams.rb +1 -1
- data/lib/tempest_time/helpers/time_helper.rb +32 -29
- data/lib/tempest_time/version.rb +1 -1
- metadata +2 -3
- data/lib/tempest_time/services/generate_report.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8fadd5695c98443d2892aac9bdc9a907ff1825d8613c0955ce988af14386f0df
|
4
|
+
data.tar.gz: add6d9dc10500fc6236030b5da61c24003fe57a49896062cf7894e5e9d983372
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0742fd8630fc7744e7b814ff28b0b6498a0245cdf8b72e3b819d182001eae5281db7cb3785e03d91a8fa199f37e43b98d5078e3fe29921c2d8bfd3ef62426dac
|
7
|
+
data.tar.gz: 53060657cdcf5f6a524dfeb360e78cc38b9b2a6c78963d762d3a0d2acfc2d07ef5b69fa6687510d7b5e33b5563ee22e98fbf151d44a6a2ba3e0783baf2a41f81
|
data/Gemfile.lock
CHANGED
@@ -7,12 +7,12 @@ module TempoAPI
|
|
7
7
|
class SubmitTimesheet < TempoAPI::Request
|
8
8
|
include TempestTime::Helpers::TimeHelper
|
9
9
|
|
10
|
-
attr_reader :reviewer, :
|
10
|
+
attr_reader :reviewer, :dates
|
11
11
|
|
12
|
-
def initialize(reviewer,
|
12
|
+
def initialize(reviewer, dates)
|
13
13
|
super
|
14
14
|
@reviewer = reviewer
|
15
|
-
@
|
15
|
+
@dates = dates
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -30,7 +30,6 @@ module TempoAPI
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def query_params
|
33
|
-
dates = week_dates(week_number)
|
34
33
|
{
|
35
34
|
from: dates.first.strftime(DATE_FORMAT),
|
36
35
|
to: dates.last.strftime(DATE_FORMAT)
|
@@ -7,7 +7,7 @@ module TempoAPI
|
|
7
7
|
class ListWorklogs < TempoAPI::Response
|
8
8
|
include TempestTime::Helpers::TimeHelper
|
9
9
|
|
10
|
-
attr_reader :worklogs
|
10
|
+
attr_reader :worklogs, :total_hours_spent
|
11
11
|
|
12
12
|
def worklogs
|
13
13
|
@worklogs ||= raw_response['results'].map do |worklog|
|
@@ -20,18 +20,6 @@ module TempoAPI
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
private
|
24
|
-
|
25
|
-
def success_message
|
26
|
-
output = ""
|
27
|
-
output << worklogs_output
|
28
|
-
output << "\nTOTAL TIME LOGGED: #{total_hours_spent} hours."
|
29
|
-
end
|
30
|
-
|
31
|
-
def worklogs_output
|
32
|
-
worklogs.map(&:to_s).join("\n")
|
33
|
-
end
|
34
|
-
|
35
23
|
def total_hours_spent
|
36
24
|
worklogs.map(&:hours).reduce(:+)&.round(2) || 0
|
37
25
|
end
|
data/lib/tempest_time/cli.rb
CHANGED
@@ -23,17 +23,11 @@ module TempestTime
|
|
23
23
|
'teams', 'teams [SUBCOMMAND]',
|
24
24
|
'Add or modify teams.'
|
25
25
|
|
26
|
-
desc 'list
|
27
|
-
|
28
|
-
|
29
|
-
e.g. `tempest list today`\n
|
30
|
-
e.g. `tempest list yesterday`\n
|
31
|
-
e.g. `tempest list 2019-01-31`\n
|
32
|
-
e.g. `tempest list 2019-01-31 --user=jsmith`
|
33
|
-
LONGDESC
|
34
|
-
def list(date = nil)
|
26
|
+
desc 'list', 'List worklogs for a specific date.'
|
27
|
+
option :user, aliases: '-u', type: :string
|
28
|
+
def list
|
35
29
|
require_relative 'commands/list'
|
36
|
-
TempestTime::Commands::List.new(
|
30
|
+
TempestTime::Commands::List.new(options).execute
|
37
31
|
end
|
38
32
|
|
39
33
|
|
data/lib/tempest_time/command.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
|
+
require_relative 'helpers/time_helper'
|
5
|
+
require_relative 'helpers/formatting_helper'
|
4
6
|
|
5
7
|
module TempestTime
|
6
8
|
class Command
|
7
9
|
extend Forwardable
|
10
|
+
include TempestTime::Helpers::TimeHelper
|
11
|
+
include TempestTime::Helpers::FormattingHelper
|
8
12
|
|
9
13
|
def_delegators :command, :run
|
10
14
|
|
@@ -30,6 +34,26 @@ module TempestTime
|
|
30
34
|
TTY::Prompt.new(options)
|
31
35
|
end
|
32
36
|
|
37
|
+
def week_prompt(message, past_weeks = 51)
|
38
|
+
require 'tty-prompt'
|
39
|
+
weeks = past_week_selections(past_weeks)
|
40
|
+
TTY::Prompt.new.select(
|
41
|
+
message,
|
42
|
+
weeks,
|
43
|
+
per_page: 5
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def date_prompt(message, past_days = 6)
|
48
|
+
require 'tty-prompt'
|
49
|
+
dates = past_date_selections(past_days)
|
50
|
+
TTY::Prompt.new.select(
|
51
|
+
message,
|
52
|
+
dates,
|
53
|
+
per_page: 5
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
33
57
|
def spinner
|
34
58
|
require 'tty-spinner'
|
35
59
|
TTY::Spinner
|
@@ -9,24 +9,52 @@ module TempestTime
|
|
9
9
|
class List < TempestTime::Command
|
10
10
|
include TempestTime::Helpers::TimeHelper
|
11
11
|
|
12
|
-
def initialize(
|
13
|
-
@date = date
|
12
|
+
def initialize(options)
|
14
13
|
@options = options
|
15
14
|
end
|
16
15
|
|
17
16
|
def execute(input: $stdin, output: $stdout)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@
|
17
|
+
@date ||= date_prompt('Please select a date.')
|
18
|
+
|
19
|
+
with_spinner("Retrieving logs for #{formatted_date(@date)}...") do |spin|
|
20
|
+
@response = TempoAPI::Requests::ListWorklogs.new(
|
21
|
+
@date,
|
22
|
+
nil,
|
23
23
|
@options[:user]
|
24
|
+
).send_request
|
25
|
+
spin.stop(pastel.green('Done!'))
|
26
|
+
prompt.say(render_table)
|
27
|
+
prompt.say(
|
28
|
+
'Total Time Logged: '\
|
29
|
+
"#{pastel.green("#{@response.total_hours_spent} hours")}"
|
24
30
|
)
|
25
|
-
request.send_request
|
26
|
-
puts "\nHere are your logs for #{formatted_date_range(start_date, @options['end_date'])}:\n"
|
27
|
-
puts request.response_message
|
28
31
|
end
|
29
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def table_headings
|
37
|
+
%w[Worklog Issue Time Description]
|
38
|
+
end
|
39
|
+
|
40
|
+
def render_table
|
41
|
+
t = table.new(table_headings, @response.worklogs.map { |r| row(r) })
|
42
|
+
t.render(
|
43
|
+
:ascii,
|
44
|
+
padding: [0, 1],
|
45
|
+
column_widths: [7,10,15,30],
|
46
|
+
multiline: true
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def row(worklog)
|
51
|
+
[
|
52
|
+
worklog.id,
|
53
|
+
worklog.issue,
|
54
|
+
formatted_time(worklog.seconds),
|
55
|
+
worklog.description
|
56
|
+
]
|
57
|
+
end
|
30
58
|
end
|
31
59
|
end
|
32
60
|
end
|
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require_relative '../command'
|
4
4
|
require_relative '../settings/teams'
|
5
|
-
require_relative '../services/generate_report'
|
6
5
|
require_relative '../helpers/time_helper'
|
6
|
+
require_relative '../api/tempo_api/requests/list_worklogs'
|
7
|
+
require_relative '../models/report'
|
7
8
|
|
8
9
|
module TempestTime
|
9
10
|
module Commands
|
@@ -13,7 +14,6 @@ module TempestTime
|
|
13
14
|
def initialize(users, options)
|
14
15
|
@users = users || []
|
15
16
|
@team = options[:team]
|
16
|
-
@week = options[:week]
|
17
17
|
end
|
18
18
|
|
19
19
|
def execute(input: $stdin, output: $stdout)
|
@@ -21,14 +21,14 @@ module TempestTime
|
|
21
21
|
@users.push(TempestTime::Settings::Teams.members(@team)) if @team
|
22
22
|
abort('No users specified.') unless @users.any?
|
23
23
|
|
24
|
-
@week
|
24
|
+
@week = week_prompt('Please select the week to report.')
|
25
25
|
|
26
26
|
with_spinner('Generating report...') do |spinner|
|
27
27
|
table = render_table
|
28
28
|
spinner.stop(pastel.green('Your report is ready!'))
|
29
|
-
date_range = "#{formatted_date(
|
29
|
+
date_range = "#{formatted_date(start_date)}"\
|
30
30
|
' to '\
|
31
|
-
"#{formatted_date(
|
31
|
+
"#{formatted_date(end_date)}"
|
32
32
|
prompt.say("\nReport for #{pastel.green(date_range)}")
|
33
33
|
puts table
|
34
34
|
end
|
@@ -36,61 +36,92 @@ module TempestTime
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def report
|
40
|
-
@report ||= TempestTime::Services::GenerateReport.new(
|
41
|
-
@users.flatten, @week
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
39
|
def user_prompt
|
46
40
|
type = prompt.select(
|
47
|
-
|
48
|
-
|
41
|
+
'Generate a report for a '\
|
42
|
+
"#{pastel.green('team')} or a specific #{pastel.green('user')}?",
|
43
|
+
%w[Team User]
|
49
44
|
)
|
50
|
-
|
45
|
+
|
46
|
+
if type == 'User'
|
47
|
+
return [
|
48
|
+
prompt.ask("Please enter a #{pastel.green('user')}.")
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
51
52
|
teams = TempestTime::Settings::Teams
|
52
|
-
|
53
|
+
if teams.keys.empty?
|
54
|
+
abort('You have no teams yet! Go make one! (tempest teams add)')
|
55
|
+
end
|
56
|
+
|
53
57
|
team = prompt.select(
|
54
|
-
"
|
58
|
+
"Please select a #{pastel.green('team')}.",
|
55
59
|
teams.keys
|
56
60
|
)
|
57
61
|
teams.members(team)
|
58
62
|
end
|
59
63
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
def start_date
|
65
|
+
@start_date ||= week_dates(@week).first
|
66
|
+
end
|
67
|
+
|
68
|
+
def end_date
|
69
|
+
@end_date ||= week_dates(@week).last
|
70
|
+
end
|
71
|
+
|
72
|
+
def reports
|
73
|
+
@reports ||= @users.map do |user|
|
74
|
+
list = TempoAPI::Requests::ListWorklogs.new(
|
75
|
+
start_date,
|
76
|
+
end_date,
|
77
|
+
user
|
78
|
+
).send_request
|
79
|
+
TempestTime::Models::Report.new(user, list.worklogs)
|
80
|
+
end || []
|
81
|
+
end
|
82
|
+
|
83
|
+
def aggregate
|
84
|
+
@aggregate ||= TempestTime::Models::Report.new(
|
85
|
+
'TOTAL',
|
86
|
+
reports.flat_map(&:worklogs),
|
87
|
+
@users.count
|
66
88
|
)
|
67
|
-
|
89
|
+
end
|
90
|
+
|
91
|
+
def projects
|
92
|
+
@projects ||= reports.flat_map(&:projects).uniq
|
68
93
|
end
|
69
94
|
|
70
95
|
def table_headings
|
71
|
-
%w[User COMP% UTIL%] +
|
96
|
+
%w[User COMP% UTIL%] + projects
|
72
97
|
end
|
73
98
|
|
74
99
|
def render_table
|
75
100
|
t = table.new(
|
76
101
|
table_headings,
|
77
|
-
|
102
|
+
reports.map { |r| row(r) } + [row(aggregate)]
|
78
103
|
)
|
79
104
|
|
80
105
|
t.render(:ascii, padding: [0, 1])
|
81
106
|
end
|
82
107
|
|
83
|
-
def row(
|
108
|
+
def row(data)
|
84
109
|
row = [
|
85
|
-
|
86
|
-
|
87
|
-
|
110
|
+
data.user,
|
111
|
+
percentage(data.total_compliance_percentage),
|
112
|
+
percentage(data.utilization_percentage)
|
88
113
|
]
|
89
|
-
|
90
|
-
row.push(
|
114
|
+
projects.each do |project|
|
115
|
+
row.push(
|
116
|
+
percentage(data.project_compliance_percentages.to_h.fetch(project, 0))
|
117
|
+
)
|
91
118
|
end
|
92
119
|
row
|
93
120
|
end
|
121
|
+
|
122
|
+
def percentage(decimal)
|
123
|
+
(decimal * 100).to_i.to_s + '%'
|
124
|
+
end
|
94
125
|
end
|
95
126
|
end
|
96
127
|
end
|
@@ -16,28 +16,16 @@ module TempestTime
|
|
16
16
|
def execute(input: $stdin, output: $stdout)
|
17
17
|
# Command logic goes here ...
|
18
18
|
reviewer = prompt.ask('Who should review this timesheet? (username)')
|
19
|
-
|
19
|
+
dates = week_dates(week_prompt('Select a week to submit.'))
|
20
20
|
|
21
21
|
message = 'Submit the selected timesheet to ' + pastel.green(reviewer) + '?'
|
22
22
|
abort unless prompt.yes?(message)
|
23
23
|
abort unless prompt.yes?('Are you sure? No edits can be made once submitted!')
|
24
24
|
|
25
25
|
with_success_fail_spinner("Submitting your timesheet...") do
|
26
|
-
TempoAPI::Requests::SubmitTimesheet.new(reviewer,
|
26
|
+
TempoAPI::Requests::SubmitTimesheet.new(reviewer, dates).send_request
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def week_prompt
|
33
|
-
week = TTY::Prompt.new.select(
|
34
|
-
'Please select the week to submit.',
|
35
|
-
week_ranges,
|
36
|
-
default: current_week,
|
37
|
-
per_page: 5
|
38
|
-
)
|
39
|
-
week_ranges.find_index(week) + 1
|
40
|
-
end
|
41
29
|
end
|
42
30
|
end
|
43
31
|
end
|
@@ -20,7 +20,7 @@ module TempestTime
|
|
20
20
|
TempestTime::Commands::Teams::Edit.new(options).execute
|
21
21
|
end
|
22
22
|
|
23
|
-
desc 'delete', '
|
23
|
+
desc 'delete', 'Delete a team.'
|
24
24
|
def delete(*)
|
25
25
|
require_relative 'teams/delete'
|
26
26
|
TempestTime::Commands::Teams::Delete.new(options).execute
|
@@ -13,11 +13,15 @@ module TempestTime
|
|
13
13
|
return time.chomp('m').to_i * 60
|
14
14
|
end
|
15
15
|
|
16
|
-
abort(
|
16
|
+
abort('Please provide time in the correct format. e.g. 0.5h, .5h, 30m')
|
17
17
|
end
|
18
18
|
|
19
19
|
def formatted_time(seconds)
|
20
|
-
seconds < 3600
|
20
|
+
if seconds < 3600
|
21
|
+
"#{seconds / 60} minutes"
|
22
|
+
else
|
23
|
+
"#{(seconds / 3600.to_f).round(2)} hours"
|
24
|
+
end
|
21
25
|
end
|
22
26
|
|
23
27
|
def formatted_date_range(start_date, end_date)
|
@@ -26,46 +30,45 @@ module TempestTime
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def formatted_date(date)
|
29
|
-
|
33
|
+
Date::DAYNAMES[date.wday] +
|
34
|
+
', ' +
|
35
|
+
Date::MONTHNAMES[date.month] +
|
36
|
+
' ' +
|
37
|
+
date.day.to_s
|
30
38
|
end
|
31
39
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
[Date.today]
|
36
|
-
when 'yesterday'
|
37
|
-
[Date.today.prev_day]
|
38
|
-
when 'week', 'thisweek'
|
39
|
-
week_dates(current_week)
|
40
|
-
when 'lastweek'
|
41
|
-
week_dates(current_week - 1)
|
42
|
-
else
|
43
|
-
[Date.parse(date_input)]
|
44
|
-
end
|
40
|
+
def beginning_of_week(weeks_ago = 0)
|
41
|
+
return unless weeks_ago >= 0
|
42
|
+
(Date.today - Date.today.wday) - (weeks_ago * 7)
|
45
43
|
end
|
46
44
|
|
47
|
-
def
|
48
|
-
|
49
|
-
@current_week ||= (Date.today + 1).cweek
|
45
|
+
def end_of_week(weeks_ago = 0)
|
46
|
+
beginning_of_week(weeks_ago) + 6
|
50
47
|
end
|
51
48
|
|
52
|
-
def
|
53
|
-
|
54
|
-
(Date.today - Date.today.wday) - ((current_week - week_number) * 7)
|
49
|
+
def week_beginnings(number_of_weeks)
|
50
|
+
(0..number_of_weeks).map { |weeks_ago| beginning_of_week(weeks_ago) }
|
55
51
|
end
|
56
52
|
|
57
|
-
def
|
58
|
-
|
53
|
+
def past_week_selections(number_of_weeks)
|
54
|
+
weeks = {}
|
55
|
+
week_beginnings(number_of_weeks).each do |beginning|
|
56
|
+
weeks[formatted_date_range(beginning, beginning + 6)] = beginning
|
57
|
+
end
|
58
|
+
weeks
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
61
|
+
def past_date_selections(number_of_days)
|
62
|
+
dates = {}
|
63
|
+
(0..number_of_days).each do |n|
|
64
|
+
date = Date.today - n
|
65
|
+
dates[formatted_date(date)] = date
|
64
66
|
end
|
67
|
+
dates
|
65
68
|
end
|
66
69
|
|
67
|
-
def week_dates(
|
68
|
-
(0..6).map { |days|
|
70
|
+
def week_dates(first_day)
|
71
|
+
(0..6).map { |days| first_day + days }
|
69
72
|
end
|
70
73
|
end
|
71
74
|
end
|
data/lib/tempest_time/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tempest_time
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Devan Hurst
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -466,7 +466,6 @@ files:
|
|
466
466
|
- lib/tempest_time/helpers/formatting_helper.rb
|
467
467
|
- lib/tempest_time/helpers/time_helper.rb
|
468
468
|
- lib/tempest_time/models/report.rb
|
469
|
-
- lib/tempest_time/services/generate_report.rb
|
470
469
|
- lib/tempest_time/setting.rb
|
471
470
|
- lib/tempest_time/settings/authorization.rb
|
472
471
|
- lib/tempest_time/settings/teams.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require_relative '../helpers/time_helper'
|
2
|
-
require_relative '../api/tempo_api/requests/list_worklogs'
|
3
|
-
require_relative '../models/report'
|
4
|
-
|
5
|
-
module TempestTime
|
6
|
-
module Services
|
7
|
-
class GenerateReport
|
8
|
-
include TempestTime::Helpers::TimeHelper
|
9
|
-
|
10
|
-
attr_reader :users, :week_number, :reports
|
11
|
-
|
12
|
-
def initialize(users, week_number)
|
13
|
-
@users = users
|
14
|
-
@week_number = week_number || Date.today.cweek
|
15
|
-
@reports = build_reports
|
16
|
-
end
|
17
|
-
|
18
|
-
def projects
|
19
|
-
@projects ||= reports.flat_map(&:projects).uniq
|
20
|
-
end
|
21
|
-
|
22
|
-
def aggregate
|
23
|
-
@aggregate ||= TempestTime::Models::Report.new(
|
24
|
-
'TOTAL',
|
25
|
-
reports.flat_map(&:worklogs),
|
26
|
-
users.count
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
30
|
-
def start_date
|
31
|
-
@start_date ||= beginning_of_week(week_number)
|
32
|
-
end
|
33
|
-
|
34
|
-
def end_date
|
35
|
-
@end_date ||= start_date + 6
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def build_reports
|
41
|
-
users.map do |user|
|
42
|
-
request = TempoAPI::Requests::ListWorklogs.new(start_date, end_date, user)
|
43
|
-
request.send_request
|
44
|
-
TempestTime::Models::Report.new(user, request.response.worklogs)
|
45
|
-
end || []
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|