dude-cli 0.5.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +4 -3
  4. data/CHANGELOG.md +25 -0
  5. data/Gemfile +3 -2
  6. data/Gemfile.lock +55 -50
  7. data/README.md +41 -25
  8. data/bin/dude +3 -2
  9. data/dude.gemspec +18 -18
  10. data/lib/dude.rb +12 -2
  11. data/lib/dude/commands.rb +24 -0
  12. data/lib/dude/commands/checkout.rb +21 -0
  13. data/lib/dude/commands/install.rb +57 -0
  14. data/lib/dude/commands/move.rb +15 -0
  15. data/lib/dude/commands/start.rb +29 -0
  16. data/lib/dude/commands/stop.rb +15 -0
  17. data/lib/dude/commands/tasks.rb +31 -0
  18. data/lib/dude/commands/track.rb +28 -0
  19. data/lib/dude/commands/version.rb +11 -0
  20. data/lib/dude/git.rb +3 -18
  21. data/lib/dude/git/checkout.rb +9 -0
  22. data/lib/dude/git/current_branch_name.rb +9 -0
  23. data/lib/dude/project_management/client.rb +25 -0
  24. data/lib/dude/project_management/entities/board.rb +9 -0
  25. data/lib/dude/project_management/entities/issue.rb +37 -0
  26. data/lib/dude/project_management/jira.rb +9 -0
  27. data/lib/dude/project_management/jira/client.rb +49 -0
  28. data/lib/dude/project_management/jira/get_current_tasks.rb +40 -0
  29. data/lib/dude/project_management/jira/get_task_name_by_id.rb +24 -0
  30. data/lib/dude/project_management/jira/move_task_to_list.rb +47 -0
  31. data/lib/dude/project_management/trello.rb +6 -0
  32. data/lib/dude/project_management/trello/checkout.rb +4 -0
  33. data/lib/dude/project_management/trello/client.rb +33 -0
  34. data/lib/dude/project_management/trello/get_current_tasks.rb +24 -0
  35. data/lib/dude/project_management/trello/get_lists.rb +15 -0
  36. data/lib/dude/project_management/trello/move_tasks_to_list.rb +14 -0
  37. data/lib/dude/settings.rb +6 -2
  38. data/lib/dude/time_trackers/toggl.rb +5 -0
  39. data/lib/dude/time_trackers/toggl/base.rb +18 -0
  40. data/lib/dude/time_trackers/toggl/start_time_entry.rb +53 -0
  41. data/lib/dude/time_trackers/toggl/stop_time_entry.rb +30 -0
  42. data/lib/dude/version.rb +1 -1
  43. metadata +59 -90
  44. data/LICENSE.txt +0 -21
  45. data/lib/dude/cli.rb +0 -114
  46. data/lib/dude/gitlab.rb +0 -82
  47. data/lib/dude/interface.rb +0 -98
  48. data/lib/dude/report.rb +0 -38
  49. data/lib/dude/toggl.rb +0 -81
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,114 +0,0 @@
1
- require 'thor'
2
- require "dude/version"
3
- require 'colorize'
4
- require_relative 'gitlab'
5
- require_relative 'git'
6
- require_relative 'toggl'
7
- require_relative 'settings'
8
- require_relative 'interface'
9
-
10
- module Dude
11
- class CLI < Thor
12
- include Settings
13
- desc 'install', 'create .duderc file in your home directory'
14
- def install
15
- path = File.join(Dir.home, Settings::CONFIG_FILE)
16
- if File.exist?(path)
17
- puts "Config file already exists"
18
- else
19
- File.open(path, 'w') {|f| f.write(duderc_file_content) }
20
- puts ".duderc created in your HOME directory"
21
- end
22
- end
23
-
24
- desc 'checkout [ISSUE_ID]', 'checkout to branch with name "ID-issue-title"'
25
- def checkout(issue_id, project_title = folder_name)
26
- issue_title = get_issue_title(issue_id, project_title)
27
- branch_name = git_branch_name(issue_title, issue_id)
28
- git(branch_name).call
29
- puts "Branch changed to '#{branch_name}'".colorize(:green)
30
- end
31
-
32
- desc 'start [ISSUE_ID]', 'do checkout, track and move actions'
33
- def start(issue_id, project_title = folder_name)
34
- checkout(issue_id, project_title)
35
- track(issue_id, project_title)
36
- move('Doing', issue_id, project_title)
37
- end
38
-
39
- desc 'track [ISSUE_ID]', 'start task in Toggl with issue title'
40
- def track(issue_id, project_title = folder_name)
41
- issue_title = get_issue_title(issue_id, project_title)
42
- Toggl.new(title: "##{issue_id} #{issue_title}", project_title: project_title).start_time_entry
43
- puts "Toggl task '#{get_issue_title(issue_id, project_title)}' is started".colorize(:green)
44
- end
45
-
46
- desc 'tasks', 'Show issues in current project assigned to you'
47
- def tasks(project_title = folder_name)
48
- issues = Gitlab.new(project_title: project_title).my_issues
49
- Interface.new.issues_list(issues)
50
- end
51
-
52
- desc 'estimate [DURATION] [ISSUE_ID]', 'estimate time'
53
- def estimate(duration, issue_id = current_issue_id, project_title = folder_name)
54
- Gitlab.new(issue_id: issue_id, project_title: project_title).estimate_time(duration)
55
- puts "Changed time estimate to #{duration}".colorize(:green)
56
- end
57
-
58
- desc 'stop', 'stop current time entry in Toggl, move issue to `To Do`'
59
- def stop(project_title = folder_name)
60
- Toggl.new.stop_current_time_entry
61
- move('To Do', current_issue_id, project_title)
62
- puts 'Work suspended'
63
- end
64
-
65
- desc 'issue', 'Information about issue'
66
- def issue(issue_id = current_issue_id, project_title = folder_name)
67
- Gitlab.new(issue_id: issue_id, project_title: project_title).issue_info
68
- end
69
-
70
- desc 'stats', 'display your stats from Toggl'
71
- def stats
72
- Toggl.new.report
73
- end
74
-
75
- desc 'move', 'move issue to another column'
76
- def move(label, issue_id = current_issue_id, project_title = folder_name)
77
- Gitlab.new(issue_id: issue_id, project_title: project_title, label: label).move_issue
78
- puts "Issue ##{issue_id} moved to '#{label}'".colorize(:green)
79
- end
80
-
81
- desc 'version', 'Show version'
82
- def version
83
- puts "Dude CLI v#{Dude::VERSION}"
84
- end
85
-
86
- private
87
-
88
- def git(branch_name)
89
- Git.new(branch_name: branch_name)
90
- end
91
-
92
- def current_issue_id
93
- Git.new.current_branch_name.chomp.split('-').first
94
- end
95
-
96
- def get_issue_title(issue_id, project_title)
97
- Gitlab.new(issue_id: issue_id, project_title: project_title).issue_title
98
- end
99
-
100
- def duderc_file_content
101
- "TOGGL_EMAIL=\nTOGGL_TOKEN=\nTOGGL_WORKSPACE_ID=\n" \
102
- "GITLAB_ENDPOINT=https://gitlab.yoursite.com/api/v4/\n" \
103
- "GITLAB_TOKEN=\nHOURS_PER_DAY=8\nHOURS_PER_WEEK=40"
104
- end
105
-
106
- def folder_name
107
- @folder_name ||= File.basename(Dir.getwd)
108
- end
109
-
110
- def git_branch_name(issue_title, issue_id)
111
- issue_title.downcase.gsub(/[^a-z0-9\-_]+/, '-').prepend("#{issue_id}-")
112
- end
113
- end
114
- end
data/lib/dude/gitlab.rb DELETED
@@ -1,82 +0,0 @@
1
- require 'gitlab'
2
- require 'colorize'
3
- require_relative 'settings'
4
- require_relative 'interface'
5
-
6
- module Dude
7
- class Gitlab
8
- include Dude::Settings
9
- attr_accessor :options
10
-
11
- def initialize(options = {})
12
- @options = options
13
- ::Gitlab.configure do |config|
14
- config.endpoint = settings['GITLAB_ENDPOINT']
15
- config.private_token = settings['GITLAB_TOKEN']
16
- end
17
- end
18
-
19
- def issue_title
20
- test_input_data
21
- ::Gitlab.issue(project_id, options[:issue_id]).title
22
- end
23
-
24
- def my_issues
25
- all_issues_on_project.select {|a| a.last.eql?(user.id) }
26
- end
27
-
28
- def estimate_time(duration)
29
- test_input_data
30
- ::Gitlab.estimate_time_of_issue(project_id, options[:issue_id], duration)
31
- time = ::Gitlab.issue(project_id, options[:issue_id]).
32
- to_h['time_stats']['human_time_estimate']
33
- Interface.new.draw_time_estimate(time)
34
- end
35
-
36
- def issue_info
37
- test_input_data
38
- issue_info = ::Gitlab.issue(project_id, options[:issue_id]).to_h
39
- Interface.new.draw_issue_info(issue_info)
40
- end
41
-
42
- def move_issue
43
- test_input_data
44
- labels = ::Gitlab.issue(project_id, options[:issue_id]).labels
45
- labels = labels.reject {|e| ['To Do', 'Doing', 'To Verify'].include?(e)}.
46
- push(options[:label]).join(',')
47
- ::Gitlab.edit_issue(project_id, options[:issue_id], { labels: labels })
48
- end
49
-
50
- private
51
-
52
- def test_input_data
53
- if options[:issue_id].to_i.zero? || !issue_exists?
54
- Interface.new.throw_error(options[:issue_id], options[:project_title])
55
- end
56
- end
57
-
58
- def issue_exists?
59
- !::Gitlab.issue(project_id, options[:issue_id]).nil?
60
- rescue
61
- nil
62
- end
63
-
64
- def all_issues_on_project
65
- ::Gitlab.issues(project_id).map {|a| [a.iid, a.title, a.labels, assignees_id(a)]}
66
- end
67
-
68
- def assignees_id(issue)
69
- issue&.assignees&.first['id']
70
- rescue NoMethodError
71
- nil
72
- end
73
-
74
- def user
75
- @my_id ||= ::Gitlab.user
76
- end
77
-
78
- def project_id
79
- @project_id ||= ::Gitlab.project_search(options[:project_title])[0]&.id
80
- end
81
- end
82
- 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
data/lib/dude/report.rb DELETED
@@ -1,38 +0,0 @@
1
- require 'date'
2
- require_relative 'settings'
3
-
4
- module Dude
5
- class Report
6
- include Settings
7
- attr_reader :report
8
-
9
- def initialize(report_json)
10
- @report = JSON.parse(report_json.body)
11
- end
12
-
13
- def week_time_worked
14
- @time_worked ||= report['total_grand'] / 1000
15
- end
16
-
17
- def today_time_worked
18
- @today_time_worked ||= report['week_totals'].map {|a| a.nil? ? 0 : a / 1000}[Time.now.wday - 1]
19
- end
20
-
21
- def days_without_weekends
22
- @days_without_weekends ||= report['week_totals'][0..Time.now.wday - 1].compact.count
23
- end
24
-
25
- def weekends
26
- @weekends ||= report['week_totals'][0..Time.now.wday - 1].
27
- select { |a| a.nil? }.count
28
- end
29
-
30
- def hours_without_weekends
31
- @hours_without_weekends ||= settings['HOURS_PER_WEEK'].to_i - weekends * settings['HOURS_PER_DAY'].to_i
32
- end
33
-
34
- def seconds_for_today
35
- days_without_weekends * settings['HOURS_PER_DAY'].to_i * 3600
36
- end
37
- end
38
- end
data/lib/dude/toggl.rb DELETED
@@ -1,81 +0,0 @@
1
- require 'rest-client'
2
- require 'date'
3
- require_relative 'settings'
4
- require_relative 'report'
5
-
6
- module Dude
7
- class Toggl
8
- include Settings
9
- attr_accessor :options
10
-
11
- def initialize(options = {})
12
- @options = options
13
- end
14
-
15
- def report
16
- report = Report.new(toggl_report.get params: report_params)
17
- Interface.new.draw_report(report)
18
- end
19
-
20
- def start_time_entry
21
- toggl_api['time_entries/start'].post time_entry_params(options[:title]).to_json, content_type: :json
22
- end
23
-
24
- def stop_current_time_entry
25
- toggl_api["time_entries/#{current_time_entry['id']}/stop"].put ''
26
- end
27
-
28
- private
29
-
30
- def report_params
31
- {
32
- workspace_id: settings['TOGGL_WORKSPACE_ID'],
33
- user_agent: settings['TOGGL_EMAIL'],
34
- since: Date.parse('monday').strftime('%Y-%m-%d')
35
- }
36
- end
37
-
38
- def time_entry_params(title)
39
- {
40
- time_entry: {
41
- description: title,
42
- pid: project_id,
43
- created_with: "dude"
44
- }
45
- }
46
- end
47
-
48
- def project_id
49
- projects_array.each do |arr|
50
- return arr.last if arr.first.eql?(options[:project_title])
51
- end
52
- nil
53
- end
54
-
55
- def current_time_entry
56
- JSON.parse(toggl_api['time_entries/current'].get)['data']
57
- end
58
-
59
- def projects_array
60
- JSON.parse(
61
- toggl_api["workspaces/#{settings['TOGGL_WORKSPACE_ID']}/projects"].get
62
- ).map { |a| [a['name'].downcase.gsub(/\s/, '-'), a['id']] }
63
- end
64
-
65
- def toggl_api
66
- @toggl_api ||= RestClient::Resource.new(
67
- 'https://www.toggl.com/api/v8',
68
- settings['TOGGL_TOKEN'],
69
- 'api_token'
70
- )
71
- end
72
-
73
- def toggl_report
74
- @toggl_report ||= RestClient::Resource.new(
75
- 'https://www.toggl.com/reports/api/v2/weekly',
76
- settings['TOGGL_TOKEN'],
77
- 'api_token'
78
- )
79
- end
80
- end
81
- end