dude-cli 1.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.gitignore +0 -1
  4. data/.travis.yml +4 -3
  5. data/CHANGELOG.md +25 -0
  6. data/Gemfile +0 -2
  7. data/Gemfile.lock +57 -50
  8. data/README.md +41 -25
  9. data/bin/dude +3 -2
  10. data/dude.gemspec +21 -19
  11. data/lib/dude.rb +14 -0
  12. data/lib/dude/commands.rb +24 -0
  13. data/lib/dude/commands/checkout.rb +21 -0
  14. data/lib/dude/commands/install.rb +57 -0
  15. data/lib/dude/commands/move.rb +15 -0
  16. data/lib/dude/commands/start.rb +29 -0
  17. data/lib/dude/commands/stop.rb +15 -0
  18. data/lib/dude/commands/tasks.rb +31 -0
  19. data/lib/dude/commands/track.rb +28 -0
  20. data/lib/dude/commands/version.rb +11 -0
  21. data/lib/dude/git.rb +5 -0
  22. data/lib/dude/git/checkout.rb +2 -16
  23. data/lib/dude/git/current_branch_name.rb +1 -2
  24. data/lib/dude/project_management/client.rb +25 -0
  25. data/lib/dude/project_management/entities/board.rb +9 -0
  26. data/lib/dude/project_management/entities/issue.rb +37 -0
  27. data/lib/dude/project_management/jira.rb +9 -0
  28. data/lib/dude/project_management/jira/client.rb +49 -0
  29. data/lib/dude/project_management/jira/get_current_tasks.rb +40 -0
  30. data/lib/dude/project_management/jira/get_task_name_by_id.rb +24 -0
  31. data/lib/dude/project_management/jira/move_task_to_list.rb +47 -0
  32. data/lib/dude/project_management/trello.rb +6 -0
  33. data/lib/dude/project_management/trello/checkout.rb +4 -0
  34. data/lib/dude/project_management/trello/client.rb +33 -0
  35. data/lib/dude/project_management/trello/get_current_tasks.rb +24 -0
  36. data/lib/dude/project_management/trello/get_lists.rb +15 -0
  37. data/lib/dude/project_management/trello/move_tasks_to_list.rb +14 -0
  38. data/lib/dude/settings.rb +6 -2
  39. data/lib/dude/time_trackers/toggl.rb +5 -0
  40. data/lib/dude/time_trackers/toggl/base.rb +18 -0
  41. data/lib/dude/{toggl → time_trackers/toggl}/start_time_entry.rb +14 -8
  42. data/lib/dude/{toggl → time_trackers/toggl}/stop_time_entry.rb +4 -2
  43. data/lib/dude/version.rb +1 -1
  44. metadata +72 -89
  45. data/LICENSE.txt +0 -21
  46. data/lib/dude/cli.rb +0 -156
  47. data/lib/dude/gitlab/add_spend_time.rb +0 -36
  48. data/lib/dude/gitlab/base.rb +0 -38
  49. data/lib/dude/gitlab/count_spend_time.rb +0 -13
  50. data/lib/dude/gitlab/estimate.rb +0 -20
  51. data/lib/dude/gitlab/get_issue_info.rb +0 -9
  52. data/lib/dude/gitlab/get_issue_time_spent.rb +0 -9
  53. data/lib/dude/gitlab/get_issue_title.rb +0 -14
  54. data/lib/dude/gitlab/get_my_issues.rb +0 -31
  55. data/lib/dude/gitlab/move_issue.rb +0 -37
  56. data/lib/dude/interface.rb +0 -98
  57. data/lib/dude/report.rb +0 -38
  58. data/lib/dude/service.rb +0 -18
  59. data/lib/dude/toggl.rb +0 -40
  60. data/lib/dude/toggl/base.rb +0 -28
  61. data/lib/dude/toggl/issue_spend_time.rb +0 -59
  62. data/lib/dude/toggl/report.rb +0 -25
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2017 Nikita Pupko
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/lib/dude/cli.rb DELETED
@@ -1,156 +0,0 @@
1
- require 'thor'
2
- require 'colorize'
3
- require 'gitlab'
4
- require 'git'
5
- require 'rest_client'
6
-
7
- require 'dude/service'
8
- require 'dude/settings'
9
- require 'dude/interface'
10
- require 'dude/report'
11
- require 'dude/version'
12
-
13
- require 'dude/git/checkout'
14
- require 'dude/git/current_branch_name'
15
-
16
- require 'dude/gitlab/base'
17
- require 'dude/gitlab/estimate'
18
- require 'dude/gitlab/add_spend_time'
19
- require 'dude/gitlab/get_issue_title'
20
- require 'dude/gitlab/get_issue_info'
21
- require 'dude/gitlab/move_issue'
22
- require 'dude/gitlab/get_my_issues'
23
- require 'dude/gitlab/count_spend_time'
24
-
25
- require 'dude/toggl/base'
26
- require 'dude/toggl/report'
27
- require 'dude/toggl/issue_spend_time'
28
- require 'dude/toggl/start_time_entry'
29
- require 'dude/toggl/stop_time_entry'
30
-
31
- module Dude
32
- class CLI < Thor
33
- include Settings
34
- desc 'install', 'create .duderc file in your home directory'
35
- def install
36
- path = File.join(Dir.home, Settings::CONFIG_FILE)
37
- if File.exist?(path)
38
- puts "Config file already exists"
39
- else
40
- File.open(path, 'w') {|f| f.write(duderc_file_content) }
41
- puts ".duderc created in your HOME directory"
42
- end
43
- end
44
-
45
- desc 'checkout [ISSUE_ID]', 'checkout to branch with name "ID-issue-title"'
46
- def checkout(issue_id, project_title = folder_name)
47
- issue_title = get_issue_title(issue_id, project_title)
48
- branch_name = branch_name_for_issue(issue_title, issue_id)
49
- Dude::Git::Checkout.call(branch_name: branch_name)
50
- end
51
-
52
- desc 'start [ISSUE_ID]', 'do checkout, track and move actions'
53
- def start(issue_id, project_title = folder_name)
54
- checkout(issue_id, project_title)
55
- track(issue_id, project_title)
56
- move('Doing', issue_id, project_title)
57
- end
58
-
59
- desc 'track [ISSUE_ID]', 'start task in Toggl with issue title'
60
- def track(issue_id, project_title = folder_name)
61
- issue_title = get_issue_title(issue_id, project_title)
62
- Dude::Toggl::StartTimeEntry.call(
63
- title: "#{issue_title} (##{issue_id})", project_title: project_title
64
- )
65
- end
66
-
67
- desc 'tasks', 'Show issues in current project assigned to you'
68
- def tasks(project_title = folder_name)
69
- issues = Dude::Gitlab::GetMyIssues.call(project_title: project_title)
70
- Interface.new.issues_list(issues)
71
- end
72
-
73
- desc 'estimate [DURATION] [ISSUE_ID]', 'estimate time'
74
- def estimate(duration, issue_id = current_issue_id, project_title = folder_name)
75
- Dude::Gitlab::Estimate.call(issue_id: issue_id, project_title: project_title, duration: duration)
76
- end
77
-
78
- desc 'spend [ISSUE_ID]', 'spend time'
79
- def spend(issue_id = current_issue_id, project_title = folder_name)
80
- old_data = Dude::Gitlab::CountSpendTime.call(issue_id: issue_id, project_title: project_title)
81
- new_data = Dude::Toggl::IssueSpendTime.call(issue_id: issue_id, project_title: project_title)
82
- diff = new_data - old_data
83
- Dude::Gitlab::AddSpendTime.call(duration: diff, issue_id: issue_id, project_title: project_title)
84
- end
85
-
86
- desc 'stop', 'stop current time entry in Toggl, move issue to `To Do`'
87
- def stop(issue_id = current_issue_id, project_title = folder_name)
88
- Dude::Toggl::StopTimeEntry.call
89
- move('To Do', issue_id, project_title)
90
- spend(issue_id, project_title)
91
- puts 'Work suspended'.colorize(:yellow)
92
- end
93
-
94
- desc 'finish', 'stop current time entry in Toggl, move issue to `To Verify`'
95
- def finish(issue_id = current_issue_id, project_title = folder_name)
96
- Dude::Toggl::StopTimeEntry.call
97
- move('To Verify', issue_id, project_title)
98
- spend(current_issue_id, project_title)
99
- puts "Issue ##{current_issue_id} finished".colorize(:green)
100
- end
101
-
102
- desc 'issue [ISSUE_ID]', 'Information about issue'
103
- def issue(issue_id = current_issue_id, project_title = folder_name)
104
- issue_info = Dude::Gitlab::GetIssueInfo.call(
105
- issue_id: issue_id, project_title: project_title
106
- )
107
- Interface.new.draw_issue_info(issue_info)
108
- end
109
-
110
- desc 'stats', 'display your stats from Toggl'
111
- def stats
112
- report = Dude::Toggl::Report.call
113
- Interface.new.draw_report(report)
114
- end
115
-
116
- desc 'move [LABEL] [ISSUE_ID]', 'move issue to another column'
117
- def move(label, issue_id = current_issue_id, project_title = folder_name)
118
- Dude::Gitlab::MoveIssue.call(
119
- issue_id: issue_id, project_title: project_title, label: label
120
- )
121
- end
122
-
123
- desc 'version', 'Show version'
124
- def version
125
- puts "Dude CLI v#{Dude::VERSION}"
126
- end
127
-
128
- private
129
-
130
- def git(branch_name)
131
- Git.new(branch_name: branch_name)
132
- end
133
-
134
- def current_issue_id
135
- Dude::Git::CurrentBranchName.call.chomp.split('-').first
136
- end
137
-
138
- def get_issue_title(issue_id, project_title)
139
- Dude::Gitlab::GetIssueTitle.call(issue_id: issue_id, project_title: project_title)
140
- end
141
-
142
- def duderc_file_content
143
- "TOGGL_EMAIL=\nTOGGL_TOKEN=\nTOGGL_WORKSPACE_ID=\n" \
144
- "GITLAB_ENDPOINT=https://gitlab.yoursite.com/api/v4/\n" \
145
- "GITLAB_TOKEN=\nHOURS_PER_DAY=8\nHOURS_PER_WEEK=40"
146
- end
147
-
148
- def folder_name
149
- @folder_name ||= File.basename(Dir.getwd)
150
- end
151
-
152
- def branch_name_for_issue(issue_title, issue_id)
153
- issue_title.downcase.gsub(/[^a-z0-9\-_]+/, '-').prepend("#{issue_id}-")
154
- end
155
- end
156
- end
@@ -1,36 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class AddSpendTime < Dude::Gitlab::Base
4
- def call
5
- if duration_exists?
6
- add_spend_time
7
- print_success_message
8
- else
9
- print_error_message
10
- end
11
- end
12
-
13
- def add_spend_time
14
- ::Gitlab.add_time_spent_on_issue(
15
- project_id, options[:issue_id], "#{options[:duration]}s"
16
- )
17
- end
18
-
19
- def duration_exists?
20
- options[:duration] > 0
21
- end
22
-
23
- def print_success_message
24
- puts "Added #{formatted_time} to spent time"
25
- end
26
-
27
- def print_error_message
28
- puts "Nothing to add".colorize(:yellow)
29
- end
30
-
31
- def formatted_time
32
- Time.at(options[:duration]).utc.strftime('%H:%M:%S').to_s.colorize(:green)
33
- end
34
- end
35
- end
36
- end
@@ -1,38 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class Base
4
- include Service
5
- include Settings
6
-
7
- def initialize(*)
8
- super
9
- configure_gitlab
10
- end
11
-
12
- def check_input_data
13
- throw_error if options[:issue_id].to_i.zero? || !issue_exists?
14
- end
15
-
16
- def throw_error
17
- Interface.new.throw_error(options[:issue_id], options[:project_title])
18
- end
19
-
20
- def issue_exists?
21
- !::Gitlab.issue(project_id, options[:issue_id]).nil?
22
- rescue StandardError
23
- nil
24
- end
25
-
26
- def project_id
27
- @project_id ||= ::Gitlab.project_search(options[:project_title])[0]&.id
28
- end
29
-
30
- def configure_gitlab
31
- ::Gitlab.configure do |config|
32
- config.endpoint = settings['GITLAB_ENDPOINT']
33
- config.private_token = settings['GITLAB_TOKEN']
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,13 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class CountSpendTime < Dude::Gitlab::Base
4
- def call
5
- time_stats.total_time_spent.to_i
6
- end
7
-
8
- def time_stats
9
- ::Gitlab.time_stats_for_issue(project_id, options[:issue_id])
10
- end
11
- end
12
- end
13
- end
@@ -1,20 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class Estimate < Dude::Gitlab::Base
4
- def call
5
- check_input_data
6
- estimate_time
7
- end
8
-
9
- def estimate_time
10
- ::Gitlab.estimate_time_of_issue(project_id, options[:issue_id], options[:duration])
11
- Interface.new.draw_time_estimate(options[:duration])
12
- end
13
-
14
- # def human_time_estimate
15
- # ::Gitlab.issue(project_id, options[:issue_id]).
16
- # to_h['time_stats']['human_time_estimate']
17
- # end
18
- end
19
- end
20
- end
@@ -1,9 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class GetIssueInfo < Dude::Gitlab::Base
4
- def call
5
- ::Gitlab.issue(project_id, options[:issue_id]).to_h
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class GetIssueInfo < Dude::Gitlab::Base
4
- def call
5
- ::Gitlab.issue(project_id, options[:issue_id]).to_h
6
- end
7
- end
8
- end
9
- end
@@ -1,14 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class GetIssueTitle < Dude::Gitlab::Base
4
- def call
5
- check_input_data
6
- issue_title
7
- end
8
-
9
- def issue_title
10
- ::Gitlab.issue(project_id, options[:issue_id]).title
11
- end
12
- end
13
- end
14
- end
@@ -1,31 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class GetMyIssues < Dude::Gitlab::Base
4
- MAX_ISSUES_PER_PAGE = 300
5
-
6
- def call
7
- my_issues
8
- end
9
-
10
- def my_issues
11
- all_issues_on_project.select {|a| a.last.eql?(user.id) }
12
- end
13
-
14
- def all_issues_on_project
15
- ::Gitlab.issues(project_id, per_page: MAX_ISSUES_PER_PAGE).map do |a|
16
- [a.iid, a.title, a.labels, assignees_id(a)]
17
- end
18
- end
19
-
20
- def user
21
- @user ||= ::Gitlab.user
22
- end
23
-
24
- def assignees_id(issue)
25
- issue&.assignees&.first['id']
26
- rescue NoMethodError
27
- nil
28
- end
29
- end
30
- end
31
- end
@@ -1,37 +0,0 @@
1
- module Dude
2
- module Gitlab
3
- class MoveIssue < Dude::Gitlab::Base
4
- DEFAULT_LABELS = ['To Do', 'Doing', 'To Verify'].freeze
5
-
6
- def call
7
- check_input_data
8
- move_issue
9
- print_message
10
- end
11
-
12
- def move_issue
13
- ::Gitlab.edit_issue(project_id, options[:issue_id], labels_options)
14
- end
15
-
16
- def labels_options
17
- { labels: new_issue_labels }
18
- end
19
-
20
- def all_issue_labels
21
- ::Gitlab.issue(project_id, options[:issue_id]).labels
22
- end
23
-
24
- def default_issue_labels
25
- all_issue_labels.reject {|e| DEFAULT_LABELS.include?(e)}
26
- end
27
-
28
- def new_issue_labels
29
- default_issue_labels.push(options[:label]).join(',')
30
- end
31
-
32
- def print_message
33
- puts "Issue ##{options[:issue_id]} moved to '#{options[:label]}'".colorize(:green)
34
- end
35
- end
36
- end
37
- end
@@ -1,98 +0,0 @@
1
- require 'colorize'
2
- require_relative 'settings'
3
-
4
- module Dude
5
- class Interface
6
- include Settings
7
-
8
- def draw_report(report)
9
- @report = report
10
- report_weekly
11
- puts ''
12
- report_daily
13
- end
14
-
15
- def throw_error(issue_id, project_title)
16
- puts "Something went wrong. Please, check input data\n".colorize(:red) +
17
- "Project: #{project_title.to_s.bold}\n" +
18
- "Issue ID: #{issue_id.to_s.bold}"
19
- exit
20
- end
21
-
22
- def draw_time_estimate(time)
23
- puts "Changed time estimate to #{time.colorize(:green)}"
24
- end
25
-
26
- def draw_issue_info(info)
27
- issue_label = info['labels'].find do |label|
28
- ['To Do', 'Doing', 'To Verify'].include? label
29
- end
30
-
31
- issue_color = case issue_label
32
- when 'To Do'
33
- :yellow
34
- when 'Doing'
35
- :green
36
- when 'To Verify'
37
- :blue
38
- end
39
-
40
- puts "#{info['title']} ##{info['iid']}".colorize(issue_color).bold
41
- puts "Status: ".colorize(:yellow) + "#{issue_label}"
42
- puts "Estimated time: ".colorize(:yellow) +
43
- "#{info['time_stats']['human_time_estimate']}"
44
- puts "Spent time: ".colorize(:yellow) +
45
- "#{info['time_stats']['human_total_time_spent'] || '0h'}"
46
- puts "Link: ".colorize(:yellow) + "#{info['web_url']}"
47
- end
48
-
49
- def issues_list(issues)
50
- [['To Do', :yellow], ['Doing', :green], ['To Verify', :blue]].each do |group, color|
51
- puts "#{group}:".colorize(color).bold
52
- grouped = issues.select {|i| i[2].include?(group)}
53
- if grouped.length.zero?
54
- puts 'Nothing'
55
- else
56
- grouped.each do |id, issue, labels|
57
- puts "#{id}:".colorize(color) + " #{issue} #{labels.compact.to_s.gsub('"', "")}"
58
- end
59
- end
60
- puts ''
61
- end
62
- end
63
-
64
- private
65
-
66
- def report_weekly
67
- puts "Week".colorize(:green).bold
68
- # puts '-' * 15
69
- puts " Worked:".colorize(:yellow).bold +
70
- " #{seconds_to_time(@report.week_time_worked)} / " \
71
- "#{@report.hours_without_weekends}:00:00 " \
72
- "(#{@report.week_time_worked * 100 / 144000}%)"
73
- puts " Time left:".colorize(:yellow).bold +
74
- " #{seconds_to_time(144000 - @report.week_time_worked)}"
75
- end
76
-
77
- def report_daily
78
- puts "Today".colorize(:green).bold
79
- # puts '-' * 15
80
- puts " Worked:".colorize(:yellow).bold +
81
- " #{seconds_to_time(@report.today_time_worked)} / " \
82
- " #{settings['HOURS_PER_DAY']}:00:00 " \
83
- "(#{@report.today_time_worked * 100 / 28800}%)"
84
- puts " Time left:".colorize(:yellow).bold +
85
- " #{seconds_to_time(@report.seconds_for_today - @report.week_time_worked)}"
86
- end
87
-
88
- def seconds_to_time(s)
89
- hms = [60,60].reduce([s]) { |m,o| m.unshift(m.shift.divmod(o)).flatten }
90
- "#{sprintf '%02d', hms[0]}:#{sprintf '%02d', hms[1]}:#{sprintf '%02d', hms[2]}"
91
- end
92
-
93
- def term
94
- term_size = IO.console.winsize
95
- @terminal = OpenStruct.new(h: term_size[0], w: term_size[1])
96
- end
97
- end
98
- end