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