tempest_time 0.6.0 → 0.6.1
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/authorization.rb +1 -1
- data/lib/tempest_time/api/jira_api/authorization.rb +4 -4
- data/lib/tempest_time/api/tempo_api/authorization.rb +3 -3
- data/lib/tempest_time/api/tempo_api/requests/create_worklog.rb +3 -3
- data/lib/tempest_time/cli.rb +13 -19
- data/lib/tempest_time/command.rb +2 -0
- data/lib/tempest_time/commands/config.rb +2 -8
- data/lib/tempest_time/commands/config/edit.rb +4 -4
- data/lib/tempest_time/commands/config/setup.rb +6 -6
- data/lib/tempest_time/commands/issue.rb +12 -13
- data/lib/tempest_time/commands/issue/list.rb +56 -0
- data/lib/tempest_time/commands/issue/open.rb +28 -0
- data/lib/tempest_time/commands/report.rb +5 -5
- data/lib/tempest_time/commands/teams/add.rb +2 -2
- data/lib/tempest_time/commands/teams/delete.rb +4 -4
- data/lib/tempest_time/commands/teams/edit.rb +9 -11
- data/lib/tempest_time/commands/track.rb +13 -21
- data/lib/tempest_time/helpers/git_helper.rb +13 -0
- data/lib/tempest_time/setting.rb +45 -42
- data/lib/tempest_time/settings/app.rb +12 -0
- data/lib/tempest_time/settings/authorization.rb +3 -10
- data/lib/tempest_time/settings/teams.rb +7 -8
- data/lib/tempest_time/version.rb +2 -2
- metadata +6 -3
- data/lib/tempest_time/commands/issues.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: ecfd390e581133802a83716b8c068cdc40e5c6890638833a253b3bfb5295726e
|
4
|
+
data.tar.gz: 464e98b2dba3d40deb03f8d66b2dd3796db5b9006cdcee46a6e98ee8a42b296f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 567a89a440c7a644945289d8c47feb749f74b10b6a3d36333ed40c7f3cf6f7498c648fac4256497f6e27544a1fc92ce70589063aedee57cd95cfa29ce63c6a38
|
7
|
+
data.tar.gz: 6762dd7c7175db615f5e783f622d9a676044e10ace1b91cbc7a56ce6fb74ddefa22fca008e2f982cf26515e4fda1b65e221ad48748013d7ce055eaebae80dc4f
|
data/Gemfile.lock
CHANGED
@@ -9,19 +9,19 @@ module JiraAPI
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def subdomain
|
12
|
-
settings.
|
12
|
+
settings.fetch('subdomain')
|
13
13
|
end
|
14
14
|
|
15
15
|
def user
|
16
|
-
settings.
|
16
|
+
settings.fetch('username')
|
17
17
|
end
|
18
18
|
|
19
19
|
def email
|
20
|
-
settings.
|
20
|
+
settings.fetch('email')
|
21
21
|
end
|
22
22
|
|
23
23
|
def token
|
24
|
-
settings.
|
24
|
+
settings.fetch('jira_token')
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -9,15 +9,15 @@ module TempoAPI
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def user
|
12
|
-
settings.
|
12
|
+
settings.fetch('username')
|
13
13
|
end
|
14
14
|
|
15
15
|
def email
|
16
|
-
settings.
|
16
|
+
settings.fetch('email')
|
17
17
|
end
|
18
18
|
|
19
19
|
def token
|
20
|
-
settings.
|
20
|
+
settings.fetch('tempo_token')
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -8,7 +8,7 @@ module TempoAPI
|
|
8
8
|
super
|
9
9
|
@seconds = seconds
|
10
10
|
@remaining = options['remaining']
|
11
|
-
@
|
11
|
+
@issue = options['issue']
|
12
12
|
@message = options['message']
|
13
13
|
@date = options['date'] ? Date.parse(options['date']) : Date.today
|
14
14
|
@billable = options['billable']
|
@@ -16,7 +16,7 @@ module TempoAPI
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
attr_reader :
|
19
|
+
attr_reader :issue, :remaining, :seconds, :message, :date, :billable
|
20
20
|
|
21
21
|
def request_method
|
22
22
|
'post'
|
@@ -32,7 +32,7 @@ module TempoAPI
|
|
32
32
|
|
33
33
|
def request_body
|
34
34
|
{
|
35
|
-
"issueKey":
|
35
|
+
"issueKey": issue,
|
36
36
|
"timeSpentSeconds": seconds,
|
37
37
|
"billableSeconds": billable_time,
|
38
38
|
"remainingEstimateSeconds": remaining,
|
data/lib/tempest_time/cli.rb
CHANGED
@@ -23,6 +23,11 @@ module TempestTime
|
|
23
23
|
'teams', 'teams [SUBCOMMAND]',
|
24
24
|
'Add or modify teams.'
|
25
25
|
|
26
|
+
require_relative 'commands/issue'
|
27
|
+
register TempestTime::Commands::Issue,
|
28
|
+
'issue', 'issue [SUBCOMMAND]',
|
29
|
+
'View and modify Jira issues.'
|
30
|
+
|
26
31
|
desc 'list', 'List worklogs for a specific date.'
|
27
32
|
option :user, aliases: '-u', type: :string
|
28
33
|
def list
|
@@ -30,7 +35,6 @@ module TempestTime
|
|
30
35
|
TempestTime::Commands::List.new(options).execute
|
31
36
|
end
|
32
37
|
|
33
|
-
|
34
38
|
desc 'submit', 'Submit your timesheet to a supervisor.'
|
35
39
|
def submit(*)
|
36
40
|
require_relative 'commands/submit'
|
@@ -57,23 +61,11 @@ module TempestTime
|
|
57
61
|
TempestTime::Commands::Delete.new(worklogs, options).execute
|
58
62
|
end
|
59
63
|
|
60
|
-
desc
|
61
|
-
def issue(issue)
|
62
|
-
require_relative 'commands/issue'
|
63
|
-
TempestTime::Commands::Issue.new(issue).execute
|
64
|
-
end
|
65
|
-
|
66
|
-
desc 'issues', "View a list of a user's assigned tickets. (Defaults to you.)"
|
67
|
-
def issues(user = nil)
|
68
|
-
require_relative 'commands/issues'
|
69
|
-
TempestTime::Commands::Issues.new(user, options).execute
|
70
|
-
end
|
71
|
-
|
72
|
-
desc "track [TIME] [TICKET(S)]", 'Track time to Tempo.'
|
64
|
+
desc "track [TIME] [ISSUE(S)]", 'Track time to Tempo.'
|
73
65
|
long_desc <<-LONGDESC
|
74
|
-
`tempest track` or `tempest log` will track the specified number of hours or minutes to the
|
75
|
-
If not specified, it will check the name of the current git branch and automatically track the logged time to that
|
76
|
-
You can also split a bank of time evenly across multiple
|
66
|
+
`tempest track` or `tempest log` will track the specified number of hours or minutes to the issue(s) specified.\n
|
67
|
+
If not specified, it will check the name of the current git branch and automatically track the logged time to that issue, if found.\n
|
68
|
+
You can also split a bank of time evenly across multiple issues with the --split flag.\n
|
77
69
|
e.g. tempest track 1.5h BCIT-1 --message='Tracking 1.5 hours.'\n
|
78
70
|
e.g. tempest log 90m BCIT-1 BCIT-2 --message='Tracking 90 minutes.'\n
|
79
71
|
e.g. tempest track 3h BCIT-1 BCIT-2 BCIT-3 --message='Tracking 1 hour.'\n
|
@@ -84,9 +76,11 @@ module TempestTime
|
|
84
76
|
option :billable, aliases: '-b', type: :boolean, default: true
|
85
77
|
option :split, aliases: '-s', type: :boolean, default: false
|
86
78
|
option :autoconfirm, type: :boolean, default: false
|
87
|
-
def track(time, *
|
79
|
+
def track(time, *issues)
|
88
80
|
require_relative 'commands/track'
|
89
|
-
TempestTime::Commands::Track.new(time,
|
81
|
+
TempestTime::Commands::Track.new(time, issues, options).execute
|
90
82
|
end
|
83
|
+
|
84
|
+
map log: :track
|
91
85
|
end
|
92
86
|
end
|
data/lib/tempest_time/command.rb
CHANGED
@@ -3,12 +3,14 @@
|
|
3
3
|
require 'forwardable'
|
4
4
|
require_relative 'helpers/time_helper'
|
5
5
|
require_relative 'helpers/formatting_helper'
|
6
|
+
require_relative 'helpers/git_helper'
|
6
7
|
|
7
8
|
module TempestTime
|
8
9
|
class Command
|
9
10
|
extend Forwardable
|
10
11
|
include TempestTime::Helpers::TimeHelper
|
11
12
|
include TempestTime::Helpers::FormattingHelper
|
13
|
+
include TempestTime::Helpers::GitHelper
|
12
14
|
|
13
15
|
def_delegators :command, :run
|
14
16
|
|
@@ -15,15 +15,9 @@ module TempestTime
|
|
15
15
|
end
|
16
16
|
|
17
17
|
desc 'edit', 'Modify your user credentials.'
|
18
|
-
method_option :help, aliases: '-h', type: :boolean,
|
19
|
-
desc: 'Display usage information'
|
20
18
|
def edit(*)
|
21
|
-
|
22
|
-
|
23
|
-
else
|
24
|
-
require_relative 'config/edit'
|
25
|
-
TempestTime::Commands::Config::Edit.new(options).execute
|
26
|
-
end
|
19
|
+
require_relative 'config/edit'
|
20
|
+
TempestTime::Commands::Config::Edit.new(options).execute
|
27
21
|
end
|
28
22
|
end
|
29
23
|
end
|
@@ -12,7 +12,7 @@ module TempestTime
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def execute(input: $stdin, output: $stdout)
|
15
|
-
settings = TempestTime::Settings::Authorization
|
15
|
+
settings = TempestTime::Settings::Authorization.new
|
16
16
|
setting = prompt.select(
|
17
17
|
"Which #{pastel.green('setting')} would you like to edit?",
|
18
18
|
settings.keys
|
@@ -20,11 +20,11 @@ module TempestTime
|
|
20
20
|
|
21
21
|
new_value = prompt.ask(
|
22
22
|
"Enter the #{pastel.green('new value')}.",
|
23
|
-
default: settings.
|
23
|
+
default: settings.fetch(setting)
|
24
24
|
)
|
25
25
|
|
26
|
-
if new_value != settings.
|
27
|
-
settings.
|
26
|
+
if new_value != settings.fetch(setting)
|
27
|
+
settings.set(setting, new_value)
|
28
28
|
prompt.say(pastel.green('Setting updated!'))
|
29
29
|
else
|
30
30
|
prompt.say('Nothing changed.')
|
@@ -39,13 +39,13 @@ module TempestTime
|
|
39
39
|
)
|
40
40
|
end
|
41
41
|
|
42
|
-
authorization = TempestTime::Settings::Authorization
|
42
|
+
authorization = TempestTime::Settings::Authorization.new
|
43
43
|
|
44
|
-
authorization.
|
45
|
-
authorization.
|
46
|
-
authorization.
|
47
|
-
authorization.
|
48
|
-
authorization.
|
44
|
+
authorization.set('email', email)
|
45
|
+
authorization.set('username', username)
|
46
|
+
authorization.set('subdomain', subdomain)
|
47
|
+
authorization.set('jira_token', jira_token)
|
48
|
+
authorization.set('tempo_token', tempo_token)
|
49
49
|
|
50
50
|
puts pastel.green('Setup complete!')
|
51
51
|
end
|
@@ -1,24 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative '../settings/authorization'
|
3
|
+
require 'thor'
|
5
4
|
|
6
5
|
module TempestTime
|
7
6
|
module Commands
|
8
|
-
class Issue <
|
9
|
-
def initialize(issue)
|
10
|
-
@issue = issue.upcase
|
11
|
-
end
|
7
|
+
class Issue < Thor
|
12
8
|
|
13
|
-
|
14
|
-
command.run("open #{url(@issue)}")
|
15
|
-
end
|
9
|
+
namespace :issue
|
16
10
|
|
17
|
-
|
11
|
+
desc 'list', 'Set up Tempest with your credentials.'
|
12
|
+
def list(*)
|
13
|
+
require_relative 'issue/list'
|
14
|
+
TempestTime::Commands::Issue::List.new(options).execute
|
15
|
+
end
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
desc 'open', 'Open an issue in your browser. (Default: current branch)'
|
18
|
+
def open(issue = '')
|
19
|
+
require_relative 'issue/open'
|
20
|
+
TempestTime::Commands::Issue::Open.new(issue).execute
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../api/jira_api/requests/get_user_issues'
|
5
|
+
|
6
|
+
module TempestTime
|
7
|
+
module Commands
|
8
|
+
class Issue
|
9
|
+
class List < TempestTime::Command
|
10
|
+
def initialize(options)
|
11
|
+
@user = options[:user] || current_user
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(input: $stdin, output: $stdout)
|
16
|
+
request = JiraAPI::Requests::GetUserIssues.new(@user)
|
17
|
+
message = "Getting issues for #{request.requested_user}"
|
18
|
+
response = with_spinner(message) do |spinner|
|
19
|
+
request.send_request.tap { spinner.stop }
|
20
|
+
end
|
21
|
+
puts format_output(response.issues)
|
22
|
+
browser_prompt(response.issues)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def browser_prompt(issues)
|
28
|
+
abort if prompt.no?('Open an issue in your browser?')
|
29
|
+
issue = prompt.select(
|
30
|
+
'Select an issue to open in browser, or press ^C to quit.',
|
31
|
+
issues.map(&:key),
|
32
|
+
per_page: 5
|
33
|
+
)
|
34
|
+
require_relative 'open'
|
35
|
+
Open.new(issue).execute
|
36
|
+
end
|
37
|
+
|
38
|
+
def format_output(issues)
|
39
|
+
table.new(
|
40
|
+
%w[Status Issue Summary],
|
41
|
+
issues.map { |issue| row(issue) }
|
42
|
+
).render(:ascii, padding: [0, 1], column_widths: [15, 10, 30])
|
43
|
+
end
|
44
|
+
|
45
|
+
def row(issue)
|
46
|
+
[issue.status, issue.key, issue.summary]
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_user
|
50
|
+
require_relative '../../settings/authorization'
|
51
|
+
TempestTime::Settings::Authorization.new.fetch('username')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../command'
|
4
|
+
require_relative '../../settings/authorization'
|
5
|
+
|
6
|
+
module TempestTime
|
7
|
+
module Commands
|
8
|
+
class Issue
|
9
|
+
class Open < TempestTime::Command
|
10
|
+
def initialize(issue)
|
11
|
+
@issue = issue.upcase
|
12
|
+
@issue = automatic_issue if issue.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(input: $stdin, output: $stdout)
|
16
|
+
command.run("open #{url(@issue)}")
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def url(issue)
|
22
|
+
domain = TempestTime::Settings::Authorization.new.fetch('subdomain')
|
23
|
+
"https://#{domain}.atlassian.net/browse/#{issue}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -14,11 +14,12 @@ module TempestTime
|
|
14
14
|
def initialize(users, options)
|
15
15
|
@users = users || []
|
16
16
|
@team = options[:team]
|
17
|
+
@teams = TempestTime::Settings::Teams.new
|
17
18
|
end
|
18
19
|
|
19
20
|
def execute(input: $stdin, output: $stdout)
|
20
21
|
@users = user_prompt if @users.empty? && @team.nil?
|
21
|
-
@users.push(
|
22
|
+
@users.push(teams.members(@team)) if @team
|
22
23
|
abort('No users specified.') unless @users.any?
|
23
24
|
|
24
25
|
@week = week_prompt('Please select the week to report.')
|
@@ -49,16 +50,15 @@ module TempestTime
|
|
49
50
|
]
|
50
51
|
end
|
51
52
|
|
52
|
-
teams
|
53
|
-
if teams.keys.empty?
|
53
|
+
if @teams.names.empty?
|
54
54
|
abort('You have no teams yet! Go make one! (tempest teams add)')
|
55
55
|
end
|
56
56
|
|
57
57
|
team = prompt.select(
|
58
58
|
"Please select a #{pastel.green('team')}.",
|
59
|
-
teams.
|
59
|
+
@teams.names
|
60
60
|
)
|
61
|
-
teams.members(team)
|
61
|
+
@teams.members(team)
|
62
62
|
end
|
63
63
|
|
64
64
|
def start_date
|
@@ -12,7 +12,7 @@ module TempestTime
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def execute(input: $stdin, output: $stdout)
|
15
|
-
teams = TempestTime::Settings::Teams
|
15
|
+
teams = TempestTime::Settings::Teams.new
|
16
16
|
message =
|
17
17
|
'Please enter ' + pastel.green('the members') + " of this team. "\
|
18
18
|
'(Comma-separated, e.g. jkirk, jpicard, bsisko, kjaneway) '
|
@@ -20,7 +20,7 @@ module TempestTime
|
|
20
20
|
q.convert ->(input) { input.split(/,\s*/) }
|
21
21
|
end
|
22
22
|
name = prompt.ask('Please enter ' + pastel.green('the name') + ' of your new team.')
|
23
|
-
teams.
|
23
|
+
teams.set(name, members)
|
24
24
|
prompt.say(pastel.green('Success!'))
|
25
25
|
end
|
26
26
|
end
|
@@ -8,18 +8,18 @@ module TempestTime
|
|
8
8
|
class Teams
|
9
9
|
class Delete < TempestTime::Command
|
10
10
|
def initialize(options)
|
11
|
+
@teams = TempestTime::Settings::Teams.new
|
11
12
|
@options = options
|
12
13
|
end
|
13
14
|
|
14
15
|
def execute(input: $stdin, output: $stdout)
|
15
|
-
teams
|
16
|
-
abort("There are no teams to delete!") unless teams.keys.any?
|
16
|
+
abort("There are no teams to delete!") unless @teams.keys.any?
|
17
17
|
team = prompt.select(
|
18
18
|
"Which #{pastel.green('team')} would you like to delete?",
|
19
|
-
teams.
|
19
|
+
@teams.names
|
20
20
|
)
|
21
21
|
if prompt.yes?(pastel.red("Are you sure you want to delete #{team}?"))
|
22
|
-
teams.delete(team)
|
22
|
+
@teams.delete(team)
|
23
23
|
prompt.say("Successfully #{pastel.red("deleted #{team}!")}")
|
24
24
|
else
|
25
25
|
abort('Nothing was deleted.')
|
@@ -12,11 +12,11 @@ module TempestTime
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def execute(input: $stdin, output: $stdout)
|
15
|
-
teams = TempestTime::Settings::Teams
|
16
|
-
abort("There are no teams to edit!") unless teams.
|
15
|
+
teams = TempestTime::Settings::Teams.new
|
16
|
+
abort("There are no teams to edit!") unless teams.names.any?
|
17
17
|
team = prompt.select(
|
18
18
|
"Which #{pastel.green('team')} would you like to edit?",
|
19
|
-
teams.
|
19
|
+
teams.names
|
20
20
|
)
|
21
21
|
|
22
22
|
members = teams.members(team)
|
@@ -25,23 +25,21 @@ module TempestTime
|
|
25
25
|
members + ['Add New Member']
|
26
26
|
)
|
27
27
|
|
28
|
-
|
28
|
+
replacement = prompt.ask(
|
29
29
|
"Enter the #{pastel.green('new name')}. "\
|
30
30
|
"Leave blank to #{pastel.red('delete')}."
|
31
31
|
)
|
32
32
|
|
33
|
-
|
33
|
+
teams.remove(team, member)
|
34
34
|
|
35
|
-
if
|
36
|
-
teams.update(team, members)
|
35
|
+
if replacement.nil?
|
37
36
|
prompt.say("Deleted #{pastel.red(member)}!")
|
38
37
|
else
|
39
|
-
|
40
|
-
|
41
|
-
prompt.say("Added #{pastel.green(replace)}")
|
38
|
+
teams.append(team, replacement)
|
39
|
+
prompt.say("Added #{pastel.green(replacement)}")
|
42
40
|
end
|
43
41
|
|
44
|
-
execute
|
42
|
+
execute unless prompt.no?('Keep editing?')
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -9,37 +9,35 @@ require_relative '../api/jira_api/requests/get_issue'
|
|
9
9
|
module TempestTime
|
10
10
|
module Commands
|
11
11
|
class Track < TempestTime::Command
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(time, tickets, options)
|
12
|
+
def initialize(time, issues, options)
|
15
13
|
@time = time
|
16
|
-
@
|
14
|
+
@issues = issues
|
17
15
|
@options = options
|
18
16
|
end
|
19
17
|
|
20
18
|
def execute(input: $stdin, output: $stdout)
|
21
|
-
time = @options[:split] ? parsed_time(@time) / @
|
22
|
-
|
19
|
+
time = @options[:split] ? parsed_time(@time) / @issues.count : parsed_time(@time)
|
20
|
+
issues = @issues.any? ? @issues.map(&:upcase) : [automatic_issue]
|
23
21
|
|
24
22
|
unless @options[:autoconfirm]
|
25
23
|
prompt_message = "Track #{formatted_time(time)}, "\
|
26
24
|
"#{billability(@options)}, "\
|
27
|
-
"to #{
|
25
|
+
"to #{issues.join(', ')}?"
|
28
26
|
abort unless prompt.yes?(prompt_message, convert: :bool)
|
29
27
|
end
|
30
28
|
|
31
|
-
|
32
|
-
track_time(time, @options.merge(
|
29
|
+
issues.each do |issue|
|
30
|
+
track_time(time, @options.merge(issue: issue))
|
33
31
|
end
|
34
32
|
end
|
35
33
|
|
36
34
|
private
|
37
35
|
|
38
36
|
def track_time(time, options)
|
39
|
-
message = "Tracking #{formatted_time(time)} to #{options['
|
37
|
+
message = "Tracking #{formatted_time(time)} to #{options['issue']}..."
|
40
38
|
with_success_fail_spinner(message) do
|
41
39
|
options['remaining'] = if options['remaining'].nil?
|
42
|
-
remaining_estimate(options['
|
40
|
+
remaining_estimate(options['issue'], time)
|
43
41
|
else
|
44
42
|
parsed_time(options['remaining'])
|
45
43
|
end
|
@@ -47,23 +45,17 @@ module TempestTime
|
|
47
45
|
end
|
48
46
|
end
|
49
47
|
|
50
|
-
def remaining_estimate(
|
51
|
-
request = JiraAPI::Requests::GetIssue.new(
|
48
|
+
def remaining_estimate(issue, time)
|
49
|
+
request = JiraAPI::Requests::GetIssue.new(issue)
|
52
50
|
request.send_request
|
53
51
|
if request.response.failure?
|
54
|
-
abort("There was an issue getting this Jira
|
55
|
-
'Please check the
|
52
|
+
abort("There was an issue getting this Jira issue.\n"\
|
53
|
+
'Please check the issue number and your credentials.')
|
56
54
|
end
|
57
55
|
remaining = request.response.issue.remaining_estimate || 0
|
58
56
|
remaining > time ? remaining - time : 0
|
59
57
|
end
|
60
58
|
|
61
|
-
def automatic_ticket
|
62
|
-
ticket = /[A-Z]+-\d+/.match(Git.open(Dir.pwd).current_branch)
|
63
|
-
abort('Ticket not found for this branch. Please specify.') unless ticket
|
64
|
-
ticket.to_s
|
65
|
-
end
|
66
|
-
|
67
59
|
def billability(options)
|
68
60
|
options['billable'] ? 'billed' : 'non-billed'
|
69
61
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module TempestTime
|
4
|
+
module Helpers
|
5
|
+
module GitHelper
|
6
|
+
def automatic_issue
|
7
|
+
issue = /[A-Z]+-\d+/.match(Git.open(Dir.pwd).current_branch)
|
8
|
+
abort('Issue not found for this branch. Please specify.') unless issue
|
9
|
+
issue.to_s.upcase
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/tempest_time/setting.rb
CHANGED
@@ -1,47 +1,50 @@
|
|
1
|
-
require '
|
1
|
+
require 'tty-config'
|
2
2
|
|
3
3
|
module TempestTime
|
4
4
|
class Setting
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@config = TTY::Config.new
|
9
|
+
config.extname = '.yml'
|
10
|
+
config.append_path(Dir.home + '/.tempest')
|
11
|
+
end
|
12
|
+
|
13
|
+
def keys
|
14
|
+
read_config { config.to_h.keys }
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch(key)
|
18
|
+
read_config { config.fetch(key) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(key)
|
22
|
+
write_config { config.delete(key) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(key, value)
|
26
|
+
write_config { config.set(key, value: value) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove(key, value)
|
30
|
+
write_config { config.remove(value, from: key) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def append(key, value)
|
34
|
+
write_config { config.append(value, to: key) }
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def read_config
|
40
|
+
config.read
|
41
|
+
yield
|
42
|
+
end
|
43
|
+
|
44
|
+
def write_config
|
45
|
+
config.read
|
46
|
+
yield
|
47
|
+
config.write(force: true)
|
45
48
|
end
|
46
49
|
end
|
47
|
-
end
|
50
|
+
end
|
@@ -3,16 +3,9 @@ require_relative '../setting'
|
|
3
3
|
module TempestTime
|
4
4
|
module Settings
|
5
5
|
class Authorization < TempestTime::Setting
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def file_name
|
10
|
-
'auth.yml'
|
11
|
-
end
|
12
|
-
|
13
|
-
def file_path
|
14
|
-
[directory_path, file_name].join('/')
|
15
|
-
end
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
config.filename = 'auth'
|
16
9
|
end
|
17
10
|
end
|
18
11
|
end
|
@@ -3,16 +3,15 @@ require_relative '../setting'
|
|
3
3
|
module TempestTime
|
4
4
|
module Settings
|
5
5
|
class Teams < TempestTime::Setting
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
config.filename = 'teams'
|
9
|
+
end
|
10
10
|
|
11
|
-
|
11
|
+
alias names keys
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
13
|
+
def members(team)
|
14
|
+
config.fetch(team)&.sort
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
data/lib/tempest_time/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module TempestTime
|
2
|
-
VERSION = '0.6.
|
3
|
-
end
|
2
|
+
VERSION = '0.6.1'.freeze
|
3
|
+
end
|
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.6.
|
4
|
+
version: 0.6.1
|
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-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -455,7 +455,8 @@ files:
|
|
455
455
|
- lib/tempest_time/commands/config/setup.rb
|
456
456
|
- lib/tempest_time/commands/delete.rb
|
457
457
|
- lib/tempest_time/commands/issue.rb
|
458
|
-
- lib/tempest_time/commands/
|
458
|
+
- lib/tempest_time/commands/issue/list.rb
|
459
|
+
- lib/tempest_time/commands/issue/open.rb
|
459
460
|
- lib/tempest_time/commands/list.rb
|
460
461
|
- lib/tempest_time/commands/report.rb
|
461
462
|
- lib/tempest_time/commands/submit.rb
|
@@ -465,9 +466,11 @@ files:
|
|
465
466
|
- lib/tempest_time/commands/teams/edit.rb
|
466
467
|
- lib/tempest_time/commands/track.rb
|
467
468
|
- lib/tempest_time/helpers/formatting_helper.rb
|
469
|
+
- lib/tempest_time/helpers/git_helper.rb
|
468
470
|
- lib/tempest_time/helpers/time_helper.rb
|
469
471
|
- lib/tempest_time/models/report.rb
|
470
472
|
- lib/tempest_time/setting.rb
|
473
|
+
- lib/tempest_time/settings/app.rb
|
471
474
|
- lib/tempest_time/settings/authorization.rb
|
472
475
|
- lib/tempest_time/settings/teams.rb
|
473
476
|
- lib/tempest_time/templates/config/.gitkeep
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../command'
|
4
|
-
require_relative '../api/jira_api/requests/get_user_issues'
|
5
|
-
require_relative './issue'
|
6
|
-
|
7
|
-
module TempestTime
|
8
|
-
module Commands
|
9
|
-
class Issues < TempestTime::Command
|
10
|
-
def initialize(user, options)
|
11
|
-
@user = user
|
12
|
-
@options = options
|
13
|
-
end
|
14
|
-
|
15
|
-
def execute(input: $stdin, output: $stdout)
|
16
|
-
request = JiraAPI::Requests::GetUserIssues.new(@user)
|
17
|
-
message = "Getting issues for #{request.requested_user}"
|
18
|
-
response = with_spinner(message) do |spinner|
|
19
|
-
request.send_request.tap { spinner.stop }
|
20
|
-
end
|
21
|
-
puts format_output(response.issues)
|
22
|
-
browser_prompt(response.issues)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def browser_prompt(issues)
|
28
|
-
abort if prompt.no?('Open an issue in your browser?')
|
29
|
-
issue = prompt.select(
|
30
|
-
'Select an issue to open in browser, or press ^C to quit.',
|
31
|
-
issues.map(&:key),
|
32
|
-
per_page: 5
|
33
|
-
)
|
34
|
-
Issue.new(issue).execute
|
35
|
-
end
|
36
|
-
|
37
|
-
def format_output(issues)
|
38
|
-
table.new(
|
39
|
-
%w[Status Issue Summary],
|
40
|
-
issues.map { |issue| row(issue) }
|
41
|
-
).render(:ascii, padding: [0, 1], column_widths: [15, 10, 30])
|
42
|
-
end
|
43
|
-
|
44
|
-
def row(issue)
|
45
|
-
[issue.status, issue.key, issue.summary]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|