tempest_time 1.2.1 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f0b28efca7d86aa211972f46715abbc9280b68b9ef899964601d31b22175240
4
- data.tar.gz: 9f244e11657b42344c22275331bde8538a247117a4c098519355f6e766bdf89d
3
+ metadata.gz: 0f7ea036a16a00b115c43380947acca1d3ed7d1b8b3e6f15ad61aec1306291a0
4
+ data.tar.gz: 2f3b83981753b1f81b75a33b5399421f967fad33898e7c5e66f25bbb270d1e3e
5
5
  SHA512:
6
- metadata.gz: 314dc7529baf6ff390c05d6429da13244015ecf6d89d840bab1063a53cddeb067fd0275a036d63320617b9de527bdfa896c409682a33c51cc0ec6313b19e0d8e
7
- data.tar.gz: 1de292852bc3af692ed108442edf035d4adae2f49a686bb12986d66413f76170d4ee13708dfb84a4e8cad124580270d47c0d76480b397ae0f92f684ba3bbd1bf
6
+ metadata.gz: b27a2c26d4dd0c4e908001649eb59c514f4a6cdf9ea8b03d2c55826e46caf5e56af1101fab6f8d7383821c577e8ab699142bd4d0e21322b792e85eeef6087a59
7
+ data.tar.gz: e522e503832c6dd7e4704c0fd2e76815e68f75f4dd6a3af0725b14a7fa82ae34dc492bc1df6a2b232f78ada460dabbb0a4c1c3c9a6301f41998fa91a70373bd0
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JiraAPI
4
+ module Models
5
+ class User
6
+ def initialize(user)
7
+ @user_data = user
8
+ end
9
+
10
+ def name
11
+ @name ||= user_data['displayName']
12
+ end
13
+
14
+ def username
15
+ @username ||= user_data['name']
16
+ end
17
+
18
+ def email
19
+ @email ||= user_data['emailAddress']
20
+ end
21
+
22
+ def account_id
23
+ @account_id ||= user_data['accountId']
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :user_data
29
+ end
30
+ end
31
+ end
@@ -31,7 +31,7 @@ module JiraAPI
31
31
  Response
32
32
  end
33
33
 
34
- def user
34
+ def auth_user
35
35
  credentials.fetch(:email, nil)
36
36
  end
37
37
 
@@ -4,11 +4,11 @@ require_relative '../responses/get_user_issues'
4
4
  module JiraAPI
5
5
  module Requests
6
6
  class GetUserIssues < JiraAPI::Request
7
- attr_reader :requested_user
7
+ attr_reader :user
8
8
 
9
- def initialize(requested_user: nil)
9
+ def initialize(user:)
10
10
  super
11
- @requested_user = requested_user || username
11
+ @user = user
12
12
  end
13
13
 
14
14
  private
@@ -23,7 +23,7 @@ module JiraAPI
23
23
 
24
24
  def query_params
25
25
  {
26
- 'jql' => "assignee=#{requested_user} AND resolution is EMPTY",
26
+ 'jql' => "assignee=#{user.username} AND resolution is EMPTY",
27
27
  'maxResults' => 100,
28
28
  }
29
29
  end
@@ -0,0 +1,33 @@
1
+ require_relative '../request'
2
+ require_relative '../responses/search_users'
3
+
4
+ module JiraAPI
5
+ module Requests
6
+ class SearchUsers < JiraAPI::Request
7
+ def initialize(query: nil)
8
+ super
9
+ @query = query
10
+ end
11
+
12
+ private
13
+
14
+ def request_method
15
+ 'get'
16
+ end
17
+
18
+ def request_path
19
+ "/user/search"
20
+ end
21
+
22
+ def query_params
23
+ {
24
+ 'query' => @query,
25
+ }
26
+ end
27
+
28
+ def response_klass
29
+ JiraAPI::Responses::SearchUsers
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,9 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../response'
4
+ require_relative '../models/user'
4
5
 
5
6
  module JiraAPI
6
7
  module Responses
7
- class GetCurrentUser < JiraAPI::Response; end
8
+ class GetCurrentUser < JiraAPI::Response
9
+ def user
10
+ @user ||= JiraAPI::Models::User.new(raw_response)
11
+ end
12
+ end
8
13
  end
9
14
  end
@@ -0,0 +1,12 @@
1
+ require_relative '../response'
2
+ require_relative '../models/user'
3
+
4
+ module JiraAPI
5
+ module Responses
6
+ class SearchUsers < JiraAPI::Response
7
+ def users
8
+ @users ||= raw_response.parsed_response.map { |user| JiraAPI::Models::User.new(user) }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -61,7 +61,7 @@ module TempestTime
61
61
  authorization_klass.new.credentials
62
62
  end
63
63
 
64
- def user
64
+ def auth_user
65
65
  credentials.fetch(:user, nil)
66
66
  end
67
67
 
@@ -82,7 +82,7 @@ module TempestTime
82
82
  end
83
83
 
84
84
  def basic_auth
85
- { username: user, password: token }
85
+ { username: auth_user, password: token }
86
86
  end
87
87
  end
88
88
  end
@@ -5,7 +5,7 @@ module TempoAPI
5
5
  private
6
6
 
7
7
  def url
8
- 'https://api.tempo.io/2'
8
+ 'https://api.tempo.io/core/3'
9
9
  end
10
10
 
11
11
  def user
@@ -15,6 +15,7 @@ module TempoAPI
15
15
  body: request_body.empty? ? request_body : request_body.to_json,
16
16
  query: query_params
17
17
  )
18
+
18
19
  response
19
20
  end
20
21
 
@@ -12,11 +12,12 @@ module TempoAPI
12
12
  @message = options[:message]
13
13
  @date = options[:date] ? options[:date] : Date.today
14
14
  @billable = options[:billable]
15
+ @user = options[:user]
15
16
  end
16
17
 
17
18
  private
18
19
 
19
- attr_reader :issue, :remaining, :seconds, :message, :date, :billable
20
+ attr_reader :issue, :remaining, :seconds, :message, :date, :billable, :user
20
21
 
21
22
  def request_method
22
23
  'post'
@@ -38,7 +39,7 @@ module TempoAPI
38
39
  "remainingEstimateSeconds": remaining,
39
40
  "startDate": date.strftime('%Y-%m-%d'),
40
41
  "startTime": '12:00:00',
41
- "authorUsername": user,
42
+ "authorAccountId": user.account_id,
42
43
  "description": message,
43
44
  }
44
45
  end
@@ -6,23 +6,23 @@ module TempoAPI
6
6
  class GetUserSchedule < TempoAPI::Request
7
7
  attr_reader :start_date, :end_date
8
8
 
9
- def initialize(start_date:, end_date:, requested_user:)
9
+ def initialize(start_date:, end_date:, user:)
10
10
  super
11
11
  @start_date = start_date
12
12
  @end_date = end_date || start_date
13
- @requested_user = requested_user || user
13
+ @user = user
14
14
  end
15
15
 
16
16
  private
17
17
 
18
- attr_reader :requested_user
18
+ attr_reader :user
19
19
 
20
20
  def request_method
21
21
  'get'
22
22
  end
23
23
 
24
24
  def request_path
25
- "/user-schedule/#{requested_user}"
25
+ "/user-schedule/#{user.account_id}"
26
26
  end
27
27
 
28
28
  def query_params
@@ -8,16 +8,16 @@ module TempoAPI
8
8
  class ListWorklogs < TempoAPI::Request
9
9
  attr_reader :start_date, :end_date
10
10
 
11
- def initialize(start_date, end_date: nil, requested_user: nil)
11
+ def initialize(start_date, end_date: nil, user: nil)
12
12
  super
13
13
  @start_date = start_date
14
14
  @end_date = end_date || start_date
15
- @requested_user = requested_user || user
15
+ @user = user
16
16
  end
17
17
 
18
18
  private
19
19
 
20
- attr_reader :requested_user
20
+ attr_reader :user
21
21
 
22
22
  def response_klass
23
23
  TempoAPI::Responses::ListWorklogs
@@ -28,7 +28,7 @@ module TempoAPI
28
28
  end
29
29
 
30
30
  def request_path
31
- "/worklogs/user/#{requested_user}"
31
+ "/worklogs/user/#{user.account_id}"
32
32
  end
33
33
 
34
34
  def query_params
@@ -7,10 +7,11 @@ module TempoAPI
7
7
  class SubmitTimesheet < TempoAPI::Request
8
8
  include TempestTime::Helpers::TimeHelper
9
9
 
10
- attr_reader :reviewer, :dates
10
+ attr_reader :submitter, :reviewer, :dates
11
11
 
12
- def initialize(reviewer, dates)
12
+ def initialize(submitter:, reviewer:, dates:)
13
13
  super
14
+ @submitter = submitter
14
15
  @reviewer = reviewer
15
16
  @dates = dates
16
17
  end
@@ -22,7 +23,7 @@ module TempoAPI
22
23
  end
23
24
 
24
25
  def request_path
25
- "/timesheet-approvals/user/#{user}/submit"
26
+ "/timesheet-approvals/user/#{submitter.account_id}/submit"
26
27
  end
27
28
 
28
29
  def response_klass
@@ -38,7 +39,7 @@ module TempoAPI
38
39
 
39
40
  def request_body
40
41
  {
41
- reviewerUsername: reviewer,
42
+ reviewerAccountId: reviewer.account_id,
42
43
  }
43
44
  end
44
45
  end
@@ -6,7 +6,7 @@ module TempoAPI
6
6
  private
7
7
 
8
8
  def success_message
9
- "Timesheet submitted successfully to #{request.reviewer}!"
9
+ "Timesheet submitted successfully to #{request.reviewer.name}!"
10
10
  end
11
11
  end
12
12
  end
@@ -5,6 +5,8 @@ require 'forwardable'
5
5
  require_relative 'helpers/time_helper'
6
6
  require_relative 'helpers/formatting_helper'
7
7
  require_relative 'helpers/git_helper'
8
+ require_relative 'api/jira_api/requests/get_current_user'
9
+ require_relative 'api/jira_api/requests/search_users'
8
10
 
9
11
  module TempestTime
10
12
  class Command
@@ -90,5 +92,31 @@ module TempestTime
90
92
  s.error(pastel.red(response.message))
91
93
  end
92
94
  end
95
+
96
+ def find_user(query)
97
+ return current_user unless query
98
+
99
+ users = JiraAPI::Requests::SearchUsers.new(query: query).send_request.users
100
+ case users.count
101
+ when 0
102
+ abort(
103
+ pastel.red('User not found!') + ' ' \
104
+ 'Please check your query and try again.'
105
+ )
106
+ when 1
107
+ return users.first
108
+ else
109
+ require 'tty-prompt'
110
+ TTY::Prompt.new.select(
111
+ pastel.yellow('Multiple users match your query. Please select a user.'),
112
+ users.map { |user| { "#{user.name}: #{user.email}" => user } },
113
+ per_page: 10
114
+ )
115
+ end
116
+ end
117
+
118
+ def current_user
119
+ @current_user ||= JiraAPI::Requests::GetCurrentUser.new.send_request.user
120
+ end
93
121
  end
94
122
  end
@@ -8,10 +8,10 @@ module TempestTime
8
8
  namespace :issue
9
9
 
10
10
  desc 'list', 'List unresolved issues.'
11
- option :date, type: :string
12
- def list(user = nil)
11
+ option :user, aliases: '-u', type: :string
12
+ def list
13
13
  require_relative 'issue/list'
14
- TempestTime::Commands::Issue::List.new(user).execute
14
+ TempestTime::Commands::Issue::List.new(options).execute
15
15
  end
16
16
 
17
17
  desc 'open', 'Open an issue in your browser. (Default: current branch)'
@@ -7,13 +7,13 @@ module TempestTime
7
7
  module Commands
8
8
  class Issue
9
9
  class List < TempestTime::Command
10
- def initialize(user)
11
- @user = user || current_user
10
+ def initialize(options)
11
+ @user = find_user(options[:user])
12
12
  end
13
13
 
14
14
  def execute!
15
- request = JiraAPI::Requests::GetUserIssues.new(requested_user: @user)
16
- message = "Getting issues for #{request.requested_user}"
15
+ request = JiraAPI::Requests::GetUserIssues.new(user: @user)
16
+ message = "Getting issues for #{pastel.yellow(@user.name)}"
17
17
  response = with_spinner(message) do |spinner|
18
18
  request.send_request.tap { spinner.stop }
19
19
  end
@@ -38,17 +38,12 @@ module TempestTime
38
38
  table.new(
39
39
  %w(Status Issue Summary),
40
40
  issues.map { |issue| row(issue) }
41
- ).render(:ascii, padding: [0, 1], column_widths: [15, 10, 30])
41
+ ).render(:ascii, padding: [0, 1], column_widths: [15, 15, 45])
42
42
  end
43
43
 
44
44
  def row(issue)
45
45
  [issue.status, issue.key, issue.summary]
46
46
  end
47
-
48
- def current_user
49
- require_relative '../../settings/authorization'
50
- TempestTime::Settings::Authorization.new.fetch('username')
51
- end
52
47
  end
53
48
  end
54
49
  end
@@ -7,7 +7,7 @@ module TempestTime
7
7
  module Commands
8
8
  class List < TempestTime::Command
9
9
  def initialize(options)
10
- @user = options[:user]
10
+ @user = find_user(options[:user])
11
11
  @dates = options[:date] ? [Date.parse(options[:date])] : nil
12
12
  end
13
13
 
@@ -18,11 +18,14 @@ module TempestTime
18
18
  days_after: 13
19
19
  ).sort
20
20
  @dates.each do |date|
21
- with_spinner("Retrieving logs for #{pastel.yellow(formatted_date(date))}...") do |spin|
21
+ with_spinner(
22
+ "Retrieving logs for #{pastel.yellow(@user.name)} "\
23
+ "on #{pastel.yellow(formatted_date(date))}..."
24
+ ) do |spin|
22
25
  @response = TempoAPI::Requests::ListWorklogs.new(
23
26
  date,
24
27
  end_date: nil,
25
- requested_user: @user
28
+ user: @user
26
29
  ).send_request
27
30
  spin.stop(pastel.green('Done!'))
28
31
  prompt.say(render_table)
@@ -45,7 +48,7 @@ module TempestTime
45
48
  t.render(
46
49
  :ascii,
47
50
  padding: [0, 1],
48
- column_widths: [7, 10, 15, 30],
51
+ column_widths: [7, 15, 15, 30],
49
52
  multiline: true
50
53
  )
51
54
  end
@@ -20,7 +20,7 @@ module TempestTime
20
20
 
21
21
  def execute!
22
22
  if @users.empty? && @team.nil?
23
- @users = user_prompt
23
+ @users = user_prompt.map { |user| find_user(user) }
24
24
  end
25
25
 
26
26
  @users.push(@teams.members(@team)) if @team
@@ -86,7 +86,7 @@ module TempestTime
86
86
  @required_seconds ||= TempoAPI::Requests::GetUserSchedule.new(
87
87
  start_date: start_date,
88
88
  end_date: end_date,
89
- requested_user: @users.first
89
+ user: @users.first
90
90
  ).send_request.required_seconds
91
91
  end
92
92
 
@@ -95,7 +95,7 @@ module TempestTime
95
95
  worklogs = TempoAPI::Requests::ListWorklogs.new(
96
96
  start_date,
97
97
  end_date: end_date,
98
- requested_user: user
98
+ user: user
99
99
  ).send_request.worklogs
100
100
 
101
101
  TempestTime::Models::Report.new(
@@ -143,7 +143,7 @@ module TempestTime
143
143
 
144
144
  def row(data)
145
145
  row = [
146
- data.user,
146
+ (data.user.is_a?(String) ? data.user : data.user.name),
147
147
  right_align(percentage(data.total_compliance_percentage)),
148
148
  right_align(percentage(data.utilization_percentage)),
149
149
  ]
@@ -72,10 +72,12 @@ module TempestTime
72
72
  end
73
73
 
74
74
  def check_for_validity
75
- jira = JiraAPI::Requests::GetCurrentUser.new
76
- tempo = TempoAPI::Requests::ListWorklogs.new(Date.today)
77
- raise StandardError unless jira.send_request.success?
78
- raise StandardError unless tempo.send_request.success?
75
+ raise StandardError unless JiraAPI::Requests::GetCurrentUser.new.send_request.user
76
+ raise StandardError unless tempo_token_is_valid?
77
+ end
78
+
79
+ def tempo_token_is_valid?
80
+ TempoAPI::Requests::ListWorklogs.new(Date.today).send_request.success?
79
81
  end
80
82
 
81
83
  def email
@@ -11,15 +11,19 @@ module TempestTime
11
11
  end
12
12
 
13
13
  def execute!
14
- reviewer = prompt.ask('Who should review this timesheet? (username)')
14
+ reviewer = find_user(prompt.ask('Who should review this timesheet?'))
15
15
  dates = week_dates(week_prompt('Select a week to submit.'))
16
16
 
17
- message = 'Submit the selected timesheet to ' + pastel.green(reviewer) + '?'
17
+ message = 'Submit the selected timesheet to ' + pastel.green(reviewer.name) + '?'
18
18
  abort unless prompt.yes?(message)
19
19
  abort unless prompt.yes?('Are you sure? No edits can be made once submitted!')
20
20
 
21
21
  with_success_fail_spinner('Submitting your timesheet...') do
22
- TempoAPI::Requests::SubmitTimesheet.new(reviewer, dates).send_request
22
+ TempoAPI::Requests::SubmitTimesheet.new(
23
+ submitter: current_user,
24
+ reviewer: reviewer,
25
+ dates: dates
26
+ ).send_request
23
27
  end
24
28
  end
25
29
  end
@@ -7,13 +7,14 @@ require_relative '../api/tempo_api/requests/create_worklog'
7
7
  module TempestTime
8
8
  module Commands
9
9
  class Track < TempestTime::Command
10
- attr_reader :time, :issues, :options
10
+ attr_reader :time, :issues, :options, :user
11
11
 
12
12
  def initialize(time, issues, options)
13
13
  @options = options
14
14
  @issues = issues.any? ? issues.map(&:upcase) : [automatic_issue]
15
15
  @time = parsed_time(time) / @issues.count
16
16
  @dates = options[:date] ? [Date.parse(options[:date])] : nil
17
+ @user = current_user
17
18
  end
18
19
 
19
20
  def execute!
@@ -24,7 +25,7 @@ module TempestTime
24
25
  end
25
26
  dates.each do |date|
26
27
  issues.each do |issue|
27
- track_time(time, options.merge({ issue: issue, date: date }))
28
+ track_time(time, options.merge({ issue: issue, date: date, user: user }))
28
29
  end
29
30
  end
30
31
  end
@@ -61,13 +62,12 @@ module TempestTime
61
62
  end
62
63
 
63
64
  def remaining_estimate(issue, time)
64
- request = JiraAPI::Requests::GetIssue.new(issue)
65
- request.send_request
66
- if request.response.failure?
67
- abort("There was an issue getting this Jira issue.\n"\
65
+ response = JiraAPI::Requests::GetIssue.new(issue).send_request
66
+ if response.failure?
67
+ abort("There was a problem getting this Jira issue.\n"\
68
68
  'Please check the issue number and your credentials.')
69
69
  end
70
- remaining = request.response.issue.remaining_estimate || 0
70
+ remaining = response.issue.remaining_estimate || 0
71
71
  remaining > time ? remaining - time : 0
72
72
  end
73
73
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TempestTime
4
- VERSION = '1.2.1'
4
+ VERSION = '2.0.0'
5
5
  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: 1.2.1
4
+ version: 2.0.0
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-03-05 00:00:00.000000000 Z
11
+ date: 2019-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -247,14 +247,17 @@ files:
247
247
  - lib/tempest_time/api/authorization.rb
248
248
  - lib/tempest_time/api/jira_api/authorization.rb
249
249
  - lib/tempest_time/api/jira_api/models/issue.rb
250
+ - lib/tempest_time/api/jira_api/models/user.rb
250
251
  - lib/tempest_time/api/jira_api/request.rb
251
252
  - lib/tempest_time/api/jira_api/requests/get_current_user.rb
252
253
  - lib/tempest_time/api/jira_api/requests/get_issue.rb
253
254
  - lib/tempest_time/api/jira_api/requests/get_user_issues.rb
255
+ - lib/tempest_time/api/jira_api/requests/search_users.rb
254
256
  - lib/tempest_time/api/jira_api/response.rb
255
257
  - lib/tempest_time/api/jira_api/responses/get_current_user.rb
256
258
  - lib/tempest_time/api/jira_api/responses/get_issue.rb
257
259
  - lib/tempest_time/api/jira_api/responses/get_user_issues.rb
260
+ - lib/tempest_time/api/jira_api/responses/search_users.rb
258
261
  - lib/tempest_time/api/request.rb
259
262
  - lib/tempest_time/api/response.rb
260
263
  - lib/tempest_time/api/tempo_api/authorization.rb