jirify 0.1.6 → 0.1.7

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: 30fe694d532ff7f42489b0e15e9c5e3baf4f3ec00f82b14a2132621bd6132bd0
4
- data.tar.gz: a01941f15a19def128da94ea49d05fd9aeace88b283c0a0c4be108ebb54874bf
3
+ metadata.gz: eb5f0f6dfffdfe5bf7ba883f13791a579a5defaaa5887cb210bb2c8d4022dbe6
4
+ data.tar.gz: 44f3bff0804ebe0a796d94417d690a3babb17fab8b3d3403a7882195defe8b67
5
5
  SHA512:
6
- metadata.gz: 4bcd7b93913fdf79bec9914d42d280c0aae9f1a237e1d7eb47d75b153181d0b26af7b61c05094d816ffd7cbcbf6090c51c45277146b874e25c69faa1a411e10a
7
- data.tar.gz: 17b11d2fff2083801a49149c615264261825bba23255cdce8ee2fcc9ce01b630a30644b0936e126be549414e65fbd1e4eece9b1d262e2f8921567aed1ca9caad
6
+ metadata.gz: 6d5069a25d999001f6e63a273d2ea32a3bd89b96b8586f77562cd4c16cd87806a892953a17e8656f460ed3b15c53ff58621a60120d95c689891f1eeecf83b85a
7
+ data.tar.gz: d4a806b94ab345ba3d89feb15f551ff8f3801a4713004331fc143b36b5abbd80ab24f1225b25561e7962c9eef8b72850413191898dd4a908e3c2b885688184a6
data/README.md CHANGED
@@ -1,10 +1,34 @@
1
1
  # jirify
2
+ [![Gem Version](https://badge.fury.io/rb/jirify.svg)](https://badge.fury.io/rb/jirify)
3
+ [![Build Status](https://travis-ci.org/GeorgeSG/jirify.svg?branch=master)](https://travis-ci.org/GeorgeSG/jirify)
4
+ [![Coverage Status](https://coveralls.io/repos/github/GeorgeSG/jirify/badge.svg?branch=master)](https://coveralls.io/github/GeorgeSG/jirify?branch=master)
5
+
2
6
  A simple ruby gem that helps me work with jira
3
7
 
4
- # How to use
8
+ ## Installation
5
9
  1. Run `gem install jirify`.
6
- 1. Execute `jira setup` and go through the setup process OR if you had the previous `config.yml` or `.jirify` file you can just move it to the `~/.jirify/` folder.
10
+ 1. Execute `jira setup` and go through the setup process.
11
+ 1. Optionally source `$HOME/.jirify/jirify.bash_completion.sh` to have autocomplete in bash.
7
12
  1. Execute `jira` and `jira <command> help` to learn about available commands.
8
13
 
9
- # To Do
14
+ ## Config Explained
15
+ Currently, the config structure of `jirify` is:
16
+ - `$HOME/.jirify` folder that contains:
17
+ - `.jirify` - yaml file generated by `jira setup`
18
+ - `jirify.bash_completion.sh` - bash completion script you can source. This is placed here by `jira setup`, so if you don't see it or you want to refresh it, run `jira setup` again.
19
+ - `.cache` - cache for completion script
20
+
21
+ ### Config file: `$HOME/.jirify/.jirify`
22
+ ```yaml
23
+ options:
24
+ username: <atlassian username (email)>
25
+ token: <token generated from https://id.atlassian.com>
26
+ site: <JIRA url>
27
+ project: <JIRA project key>
28
+ filter_by_labels:
29
+ - <label to filter by when displaying sprint>
30
+ verbose: <force jirify to always be verbose>
31
+ ```
32
+
33
+ ## To Do
10
34
  - Add ability to define mapping between custom statuses and custom transitions in config.
@@ -27,12 +27,12 @@ module Jirify
27
27
  desc: 'Show only issues with the specified statuses'
28
28
  def mine
29
29
  statuses = build_issue_statuses(options)
30
- issues = Jirify::Issue.list_mine(statuses, options[:all])
30
+ issues = Models::Issue.list_mine(statuses, options[:all])
31
31
  issues.each do |issue|
32
32
  if options[:key_only]
33
- puts issue.key
33
+ say issue.key
34
34
  else
35
- issue.print Config.always_verbose || options[:verbose]
35
+ say issue.to_s Config.always_verbose || options[:verbose]
36
36
  end
37
37
  end
38
38
  end
@@ -53,9 +53,9 @@ module Jirify
53
53
  issue = get_issue_or_exit issue_id
54
54
 
55
55
  if issue.assignee.nil?
56
- puts 'Unassigned'.yellow
56
+ say 'Unassigned'.yellow
57
57
  else
58
- puts issue.assignee.name
58
+ say issue.assignee.name
59
59
  end
60
60
  end
61
61
 
@@ -64,11 +64,11 @@ module Jirify
64
64
  issue = get_issue_or_exit issue_id
65
65
 
66
66
  if issue.assignee.nil?
67
- puts 'Issue already unassigned'.yellow
67
+ say 'Issue already unassigned'.yellow
68
68
  exit(0)
69
69
  end
70
70
 
71
- puts "Previous assignee: #{issue.assignee.name}. Unassigning..."
71
+ say "Previous assignee: #{issue.assignee.name}. Unassigning..."
72
72
  issue.unassign!
73
73
  end
74
74
 
@@ -76,7 +76,7 @@ module Jirify
76
76
  def take(issue_id)
77
77
  issue = get_issue_or_exit issue_id
78
78
 
79
- puts "Assigning #{issue.key} to #{Config.username}..."
79
+ say "Assigning #{issue.key} to #{Config.username}..."
80
80
  issue.assign_to_me!
81
81
  end
82
82
 
@@ -88,28 +88,28 @@ module Jirify
88
88
  def status(issue_id)
89
89
  issue = get_issue_or_exit issue_id
90
90
 
91
- puts issue.status.name
91
+ say "Status: #{issue.status.name}"
92
92
  end
93
93
 
94
94
  desc 'transitions [ISSUE]', 'Display available transitions'
95
95
  def transitions(issue_id)
96
96
  issue = get_issue_or_exit issue_id
97
97
 
98
- puts 'Available transitions:'
99
- puts issue.transitions.names
98
+ say 'Available transitions:'
99
+ issue.transitions.names.each { |name| say name }
100
100
  end
101
101
 
102
102
  desc 'transition [ISSUE] [TRANSITION]', 'Manually perform a transition'
103
103
  def transition(issue_id, transition_name)
104
104
  issue = get_issue_or_exit issue_id
105
- transition = issue.transitions.list.find { |t| t.name == transition_name }
105
+ transition = issue.transitions.find_by_name(transition_name)
106
106
 
107
107
  if transition.nil?
108
- puts "ERROR: Issue can't transition to #{transition_name}".red
108
+ say "ERROR: Issue can't transition to #{transition_name}".red
109
109
  exit(0)
110
110
  end
111
111
 
112
- puts "Transitioning #{issue.key} with #{transition_name}...".green
112
+ say "Transitioning #{issue.key} with #{transition_name}...".green
113
113
  issue.transition! transition
114
114
  end
115
115
 
@@ -129,10 +129,10 @@ module Jirify
129
129
  check_assigned_to_self issue
130
130
 
131
131
  if issue.blocked?
132
- puts 'Unblocking issue...'
132
+ say 'Unblocking issue...'
133
133
  issue.unblock!
134
134
  else
135
- puts 'Issue wasn\'t blocked anyway :)'.green
135
+ say 'Issue wasn\'t blocked anyway :)'.green
136
136
  end
137
137
  end
138
138
 
@@ -198,10 +198,10 @@ module Jirify
198
198
  protected
199
199
 
200
200
  def get_issue_or_exit(issue_id)
201
- issue = Jirify::Issue.find_by_id(issue_id)
201
+ issue = Models::Issue.find_by_id(issue_id)
202
202
 
203
203
  if issue.nil?
204
- puts 'ERROR: Issue not found'.red
204
+ say 'ERROR: Issue not found'.red
205
205
  exit(0)
206
206
  else
207
207
  issue
@@ -209,13 +209,13 @@ module Jirify
209
209
  end
210
210
 
211
211
  def check_assigned_to_self(issue)
212
- unless issue.mine?
213
- exit(0) unless yes? 'WARNING! This issue is not assigned to you!'\
214
- ' Are you sure you want to continue? [Y/n]:'.yellow
215
- end
212
+ return if issue.mine?
213
+
214
+ exit(0) unless yes? 'WARNING! This issue is not assigned to you!'\
215
+ ' Are you sure you want to continue? [Y/n]:'.yellow
216
216
  end
217
217
 
218
- def build_issue_statuses(options)
218
+ def build_issue_statuses(options) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
219
219
  if options[:status]
220
220
  statuses = [options[:status]]
221
221
  else
@@ -1,12 +1,12 @@
1
1
  module Jirify
2
2
  module Subcommands
3
3
  class Projects < Thor
4
+ default_task :list
5
+
4
6
  desc 'list', 'List all projects'
5
7
  def list
6
- puts Jirify::Project.all.map(&:name)
8
+ Models::Project.all.map(&:name).each { |name| say name }
7
9
  end
8
-
9
- default_task :list
10
10
  end
11
11
  end
12
12
  end
@@ -33,7 +33,7 @@ module Jirify
33
33
 
34
34
  Config.write(options)
35
35
 
36
- say "Done!"
36
+ say 'Done!'
37
37
  say "If you want to enable bash completion, source #{Config.config_folder}/jirify.bash_completion.sh"
38
38
  end
39
39
 
@@ -4,9 +4,12 @@ module Jirify
4
4
  method_option :mine, type: :boolean, aliases: '-m', desc: 'Show only issues assigned to me'
5
5
  method_option :all_columns, type: :boolean, aliases: '-a', desc: 'Show all columns'
6
6
  def sprint
7
- Jirify::Sprint.current(Config.always_verbose || options[:verbose],
8
- options[:all_columns],
9
- options[:mine])
7
+ verbose = Config.always_verbose || options[:verbose]
8
+ issues = Models::Sprint.issues_in_current_sprint(options[:mine])
9
+
10
+ say UI::SprintTable.new(issues).to_table(options[:all_columns], verbose)
11
+ rescue UI::WindowTooNarrow
12
+ say 'ERROR: Your terminal window is too narrow to print the sprint table!'.red
10
13
  end
11
14
  end
12
15
  end
data/lib/jirify/config.rb CHANGED
@@ -22,9 +22,9 @@ module Jirify
22
22
  end
23
23
 
24
24
  def initialize!
25
- FileUtils::mkdir_p CONFIG_FOLDER
26
- FileUtils::touch CONFIG_FILE
27
- FileUtils::cp "#{File.expand_path('..', File.dirname(__dir__))}/jirify.bash_completion.sh", CONFIG_FOLDER
25
+ FileUtils.mkdir_p CONFIG_FOLDER
26
+ FileUtils.touch CONFIG_FILE
27
+ FileUtils.cp "#{File.expand_path('..', File.dirname(__dir__))}/jirify.bash_completion.sh", CONFIG_FOLDER
28
28
  end
29
29
 
30
30
  def write(config)
@@ -1,28 +1,30 @@
1
1
  module Jirify
2
- class Base
3
- def initialize(entity)
4
- @entity = entity
5
- end
6
-
7
- def method_missing(method, *args, &_block)
8
- if @entity.respond_to? method
9
- @entity.send method, *args
10
- else
11
- super
2
+ module Models
3
+ class Base
4
+ def initialize(entity)
5
+ @entity = entity
12
6
  end
13
- end
14
7
 
15
- def respond_to_missing?(method, *)
16
- @entity.respond_to? method
17
- end
8
+ def method_missing(method, *args, &_block)
9
+ if @entity.respond_to? method
10
+ @entity.send method, *args
11
+ else
12
+ super
13
+ end
14
+ end
18
15
 
19
- class << self
20
- def client
21
- @client ||= JIRA::Client.new(Config.client_options)
16
+ def respond_to_missing?(method, *)
17
+ @entity.respond_to? method
22
18
  end
23
19
 
24
- def project
25
- @project ||= Config.options['project']
20
+ class << self
21
+ def client
22
+ @client ||= JIRA::Client.new(Config.client_options)
23
+ end
24
+
25
+ def project
26
+ @project ||= Config.options['project']
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -1,90 +1,92 @@
1
1
  module Jirify
2
- class Issue < Base
3
- class InvalidTransitionError < StandardError; end
2
+ module Models
3
+ class Issue < Base
4
+ class InvalidTransitionError < StandardError; end
4
5
 
5
- def mine?
6
- !assignee.nil? && assignee.emailAddress == Config.username
7
- end
6
+ def mine?
7
+ !assignee.nil? && assignee.emailAddress == Config.username
8
+ end
8
9
 
9
- def assign_to_me!
10
- @entity.assign_to!(Config.username.split('@')[0])
11
- end
10
+ def assign_to_me!
11
+ @entity.assign_to!(Config.username.split('@')[0])
12
+ end
12
13
 
13
- def unassign!
14
- @entity.assign_to!(nil)
15
- end
14
+ def unassign!
15
+ @entity.assign_to!(nil)
16
+ end
16
17
 
17
- def status
18
- @status ||= Jirify::Status.new @entity.status
19
- end
18
+ def status
19
+ @status ||= Status.new @entity.status
20
+ end
20
21
 
21
- def status?(status_name)
22
- status_name = status_name.to_s if status_name.is_a? Symbol
23
- status.name == status_name
24
- end
22
+ def status?(status_name)
23
+ status_name = status_name.to_s if status_name.is_a? Symbol
24
+ status.name == status_name
25
+ end
25
26
 
26
- Config.statuses.keys.each do |status_key|
27
- define_method "#{status_key.to_sym}?" do
28
- status.name == Config.statuses[status_key]
27
+ Config.statuses.keys.each do |status_key|
28
+ define_method "#{status_key.to_sym}?" do
29
+ status.name == Config.statuses[status_key]
30
+ end
29
31
  end
30
- end
31
32
 
32
- def transitions(reload = false)
33
- if reload
34
- @transitions = Jirify::TransitionList.all @entity
35
- else
36
- @transitions ||= Jirify::TransitionList.all @entity
33
+ def transitions(reload = false)
34
+ if reload
35
+ @transitions = TransitionList.all @entity
36
+ else
37
+ @transitions ||= TransitionList.all @entity
38
+ end
37
39
  end
38
- end
39
40
 
40
- Config.transitions.keys.each do |transition_name|
41
- define_method "#{transition_name}!".to_sym do
42
- transition = transitions(true).send(transition_name.to_sym)
41
+ Config.transitions.keys.each do |transition_name|
42
+ define_method "#{transition_name}!".to_sym do
43
+ transition = transitions(true).send(transition_name.to_sym)
43
44
 
44
- if transition.nil?
45
- puts "ERROR: Issue can't be transitioned with \"#{transition_name}\"".red
46
- exit(0)
47
- end
45
+ if transition.nil?
46
+ puts "ERROR: Issue can't be transitioned with \"#{transition_name}\"".red
47
+ exit(0)
48
+ end
48
49
 
49
- puts "Transitioning #{key} with \"#{transition_name}\"...".green
50
- @entity.transition! transition
50
+ puts "Transitioning #{key} with \"#{transition_name}\"...".green
51
+ @entity.transition! transition
52
+ end
51
53
  end
52
- end
53
54
 
54
- def print(verbose)
55
- url = "#{Config.issue_browse_url}#{key}".blue
55
+ def to_s(verbose)
56
+ url = "#{Config.issue_browse_url}#{key}".blue
56
57
 
57
- if verbose
58
- puts "#{status.pretty_name} #{key.ljust(7)}: #{summary} (#{url})"
59
- else
60
- puts "#{key.ljust(7)}: (#{url})"
58
+ if verbose
59
+ "#{status.pretty_name} #{key.ljust(7)}: #{summary} (#{url})"
60
+ else
61
+ "#{key.ljust(7)}: (#{url})"
62
+ end
61
63
  end
62
- end
63
64
 
64
- class << self
65
- def list_mine(statuses = [], all = false)
66
- my_issues = find_mine(all).sort_by { |issue| issue.status.name }
65
+ class << self
66
+ def list_mine(statuses = [], all = false)
67
+ my_issues = find_mine(all).sort_by { |issue| issue.status.name }
67
68
 
68
- my_issues.select do |issue|
69
- statuses.empty? || statuses.any? { |status| issue.status? status }
69
+ my_issues.select do |issue|
70
+ statuses.empty? || statuses.any? { |status| issue.status? status }
71
+ end
70
72
  end
71
- end
72
73
 
73
- def find_mine(all)
74
- client.Issue.jql(my_issues_jql(all)).map { |issue| Issue.new issue }
75
- end
74
+ def find_mine(all)
75
+ client.Issue.jql(my_issues_jql(all)).map { |issue| Issue.new issue }
76
+ end
76
77
 
77
- def find_by_id(issue_id)
78
- Issue.new client.Issue.find(issue_id)
79
- rescue StandardError
80
- nil
81
- end
78
+ def find_by_id(issue_id)
79
+ Issue.new client.Issue.find(issue_id)
80
+ rescue StandardError
81
+ nil
82
+ end
82
83
 
83
- protected
84
+ protected
84
85
 
85
- def my_issues_jql(all_issues)
86
- all_clause = 'AND sprint in openSprints()' unless all_issues
87
- "project='#{project}' #{all_clause} AND assignee='#{Config.username}'"
86
+ def my_issues_jql(all_issues)
87
+ all_clause = 'AND sprint in openSprints()' unless all_issues
88
+ "project='#{project}' #{all_clause} AND assignee='#{Config.username}'"
89
+ end
88
90
  end
89
91
  end
90
92
  end
@@ -1,8 +1,10 @@
1
1
  module Jirify
2
- class Project < Base
3
- class << self
4
- def all
5
- client.Project.all.map { |project| Project.new project }
2
+ module Models
3
+ class Project < Base
4
+ class << self
5
+ def all
6
+ client.Project.all.map { |project| Project.new project }
7
+ end
6
8
  end
7
9
  end
8
10
  end
@@ -1,53 +1,24 @@
1
- require 'terminal-table'
2
- require 'json'
3
-
4
1
  module Jirify
5
- class Sprint < Base
6
- class << self
7
- def current(verbose = false, all_columns = false, only_mine = false)
8
- issues = client.Issue.jql current_sprint_jql(only_mine), max_results: 200
9
-
10
- grouped_issues = issues.group_by do |issue|
11
- all_columns ? issue.status.name : issue.status.statusCategory['name']
2
+ module Models
3
+ class Sprint < Base
4
+ class << self
5
+ def issues_in_current_sprint(only_mine = false, max_results = 200)
6
+ issues = client.Issue.jql current_sprint_jql(only_mine), max_results: max_results
7
+ issues.map { |issue| Issue.new issue }
12
8
  end
13
9
 
14
- print_grouped_issues_as_table(grouped_issues, verbose)
15
- end
16
-
17
- protected
18
-
19
- def current_sprint_jql(only_mine)
20
- labels = Config.options['filter_by_labels']
21
- labels = labels.join(', ') if labels
10
+ protected
22
11
 
23
- labels_clause = "AND labels in (#{labels})" if labels
24
- mine_clause = "AND assignee='#{Config.username}'" if only_mine
25
- sprint_clause = 'AND sprint in openSprints()'
12
+ def current_sprint_jql(only_mine)
13
+ labels = Config.options['filter_by_labels']
14
+ labels = labels.join(', ') if labels
26
15
 
27
- "project='#{project}' #{sprint_clause} #{labels_clause} #{mine_clause}"
28
- end
29
-
30
- def print_grouped_issues_as_table(grouped_issues, verbose)
31
- all_groups = grouped_issues.values
32
-
33
- l = all_groups.map(&:length).max
34
- transposed = all_groups.map { |e| e.values_at(0...l) }.transpose
16
+ labels_clause = "AND labels in (#{labels})" if labels
17
+ mine_clause = "AND assignee='#{Config.username}'" if only_mine
18
+ sprint_clause = 'AND sprint in openSprints()'
35
19
 
36
- transposed = transposed.map do |row|
37
- row.map do |issue|
38
- if issue
39
- key = issue.key.ljust(7)
40
- url = "(#{Config.issue_browse_url}/#{issue.key})".blue
41
- summary = "#{issue.summary[0, 35]}...\n" if verbose
42
-
43
- "#{key}: #{summary}#{url}"
44
- else
45
- ''
46
- end
47
- end
20
+ "project='#{project}' #{sprint_clause} #{labels_clause} #{mine_clause}"
48
21
  end
49
-
50
- puts Terminal::Table.new headings: grouped_issues.keys, rows: transposed unless transposed.empty?
51
22
  end
52
23
  end
53
24
  end
@@ -1,48 +1,47 @@
1
1
  module Jirify
2
- class Status < Base
3
- def pretty_name
4
- justified = "(#{name})".rjust(longest_status_name + 2)
5
- case name
6
- when Config.statuses['blocked'] then justified.red
7
- when Config.statuses['done'] then justified.green
8
- when Config.statuses['in_progress'] then justified.blue
9
- when Config.statuses['in_review'] then justified.yellow
10
- when Config.statuses['todo'] then justified.black
11
- else justified
2
+ module Models
3
+ class Status < Base
4
+ def pretty_name
5
+ justified = "(#{name})".rjust(longest_status_name + 2)
6
+ case name
7
+ when Config.statuses['blocked'] then justified.red
8
+ when Config.statuses['done'] then justified.green
9
+ when Config.statuses['in_progress'] then justified.blue
10
+ when Config.statuses['in_review'] then justified.yellow
11
+ when Config.statuses['todo'] then justified.black
12
+ else justified
13
+ end
12
14
  end
13
- end
14
-
15
- protected
16
-
17
- def longest_status_name
18
- Config.statuses.values.map(&:length).max
19
- end
20
15
 
21
- class << self
22
- def all
23
- @all ||= client.Status.all
24
- end
16
+ def <=>(other)
17
+ this_index = Status.status_order.index(name)
18
+ other_index = Status.status_order.index(other.name)
19
+ return 1 if other_index.nil?
20
+ return 0 if this_index.nil?
25
21
 
26
- def to_do
27
- @to_do ||= find_by_name Config.statuses['todo']
22
+ this_index - other_index
28
23
  end
29
24
 
30
- def in_progress
31
- @in_progress ||= find_by_name Config.statuses['in_progress']
32
- end
33
-
34
- def in_review
35
- @in_review ||= find_by_name Config.statuses['in_review']
36
- end
25
+ protected
37
26
 
38
- def closed
39
- @closed ||= find_by_name Config.statuses['done']
27
+ def longest_status_name
28
+ Config.statuses.values.map(&:length).max
40
29
  end
41
30
 
42
- protected
43
-
44
- def find_by_name(status_name)
45
- all.select { |status| status.name == status_name }
31
+ class << self
32
+ def all
33
+ client.Status.all.map { |status| Status.new status }
34
+ end
35
+
36
+ def status_order
37
+ [
38
+ Config.statuses['blocked'],
39
+ Config.statuses['todo'],
40
+ Config.statuses['in_progress'],
41
+ Config.statuses['in_review'],
42
+ Config.statuses['done']
43
+ ]
44
+ end
46
45
  end
47
46
  end
48
47
  end
@@ -1,28 +1,30 @@
1
1
  module Jirify
2
- class TransitionList < Base
3
- attr_accessor :list
2
+ module Models
3
+ class TransitionList < Base
4
+ attr_accessor :list
4
5
 
5
- def initialize(list)
6
- @list = list
7
- end
8
-
9
- def names
10
- @list.map(&:name)
11
- end
6
+ def initialize(list)
7
+ @list = list
8
+ end
12
9
 
13
- Config.transitions.keys.each do |transition_name|
14
- define_method(transition_name.to_sym) { find_by_name transition_name }
15
- end
10
+ def find_by_name(name)
11
+ @list.find { |transition| transition.name == name }
12
+ end
16
13
 
17
- protected
14
+ def names
15
+ @list.map(&:name)
16
+ end
18
17
 
19
- def find_by_name(name)
20
- @list.find { |transition| transition.name == Config.transitions[name] }
21
- end
18
+ Config.transitions.keys.each do |transition_name|
19
+ define_method(transition_name.to_sym) do
20
+ find_by_name Config.transitions[transition_name]
21
+ end
22
+ end
22
23
 
23
- class << self
24
- def all(issue)
25
- TransitionList.new client.Transition.all(issue: issue)
24
+ class << self
25
+ def all(issue)
26
+ TransitionList.new client.Transition.all(issue: issue)
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -0,0 +1,63 @@
1
+ module Jirify
2
+ module UI
3
+ class WindowTooNarrow < StandardError; end
4
+
5
+ class SprintCell
6
+ attr_reader :issue, :max_cell_length
7
+
8
+ def initialize(issue, max_cell_length)
9
+ @issue = issue
10
+ @max_cell_length = max_cell_length
11
+ end
12
+
13
+ def key
14
+ issue.key
15
+ end
16
+
17
+ def summary
18
+ issue.summary
19
+ end
20
+
21
+ def url
22
+ "#{Config.issue_browse_url}#{issue.key}"
23
+ end
24
+
25
+ def to_s(verbose)
26
+ raise UI::WindowTooNarrow, 'The terminal window is too narrow.' if max_cell_length <= key.size
27
+
28
+ verbose ? to_verbose_cell : to_short_cell
29
+ end
30
+
31
+ protected
32
+
33
+ def display_url?
34
+ url.size <= max_cell_length
35
+ end
36
+
37
+ def to_verbose_cell
38
+ key_and_summary = "#{key}: #{summary}"
39
+
40
+ if key_and_summary.size <= max_cell_length
41
+ row = key_and_summary
42
+ else
43
+ row = "#{key}\n#{summary[0...max_cell_length - 3]}..."
44
+ end
45
+
46
+ row << "\n#{url.blue}" if display_url?
47
+ row
48
+ end
49
+
50
+ def to_short_cell
51
+ return key unless display_url?
52
+
53
+ single_row = "#{key}: #{url}"
54
+
55
+ if single_row.size <= max_cell_length
56
+ "#{key}: #{url.blue}"
57
+ else
58
+ "#{key}\n#{url.blue}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,80 @@
1
+ require 'io/console'
2
+ require 'terminal-table'
3
+
4
+ module Jirify
5
+ module UI
6
+ class SprintTable
7
+ attr_reader :issues
8
+ def initialize(issues)
9
+ @issues = issues
10
+ end
11
+
12
+ def to_table(all_columns, verbose)
13
+ grouped_issues = issues.group_by do |issue|
14
+ all_columns ? issue.status.name : issue.status.statusCategory['name']
15
+ end
16
+
17
+ grouped_issues_as_table(grouped_issues, verbose)
18
+ end
19
+
20
+ protected
21
+
22
+ def terminal_width
23
+ IO.console.winsize[1]
24
+ end
25
+
26
+ def table_style
27
+ { width: terminal_width, border_x: '-', border_i: 'x' }
28
+ end
29
+
30
+ def headings(grouped_issues)
31
+ grouped_issues.keys.sort_by do |name|
32
+ status_index = Models::Status.status_order.index(name)
33
+ if status_index.nil?
34
+ grouped_issues.keys.length
35
+ else
36
+ status_index
37
+ end
38
+ end
39
+ end
40
+
41
+ def grouped_issues_as_table(grouped_issues, verbose)
42
+ transposed = transpose(grouped_issues.values, verbose)
43
+ return nil if transposed.empty?
44
+
45
+ Terminal::Table.new(
46
+ headings: headings(grouped_issues),
47
+ rows: transposed,
48
+ style: table_style
49
+ )
50
+ end
51
+
52
+ def transpose(grouped_issues, verbose)
53
+ col_padding_per_row = grouped_issues.size * 4
54
+ max_cell_length = (terminal_width - col_padding_per_row) / grouped_issues.size
55
+
56
+ # workaround - not all groups have the same size
57
+ l = grouped_issues.map(&:length).max
58
+ grouped_as_array = grouped_issues.map { |e| e.values_at(0...l) }
59
+
60
+ grouped_as_array.sort_by! do |row|
61
+ issue = row.find { |i| !i.nil? }
62
+ issue.status
63
+ end
64
+
65
+ transposed = grouped_as_array.transpose
66
+
67
+ transposed.map! do |row|
68
+ row.map do |issue|
69
+ next if issue.nil?
70
+ SprintCell.new(issue, max_cell_length).to_s(verbose)
71
+ end
72
+ end
73
+
74
+ transposed = transposed.zip([:separator] * transposed.size).flatten(1)
75
+ transposed.pop
76
+ transposed
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module Jirify
2
- VERSION = '0.1.6'.freeze
2
+ VERSION = '0.1.7'.freeze
3
3
  end
data/lib/jirify.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'thor'
2
1
  require 'jira-ruby'
2
+ require 'thor'
3
3
  require 'colorize'
4
4
 
5
5
  require 'jirify/version'
@@ -13,6 +13,9 @@ require 'jirify/models/issue'
13
13
  require 'jirify/models/sprint'
14
14
  require 'jirify/models/project'
15
15
 
16
+ require 'jirify/ui/sprint_cell'
17
+ require 'jirify/ui/sprint_table'
18
+
16
19
  require 'jirify/cli/setup'
17
20
  require 'jirify/cli/sprint'
18
21
  require 'jirify/cli/issue'
@@ -24,7 +27,7 @@ module Jirify
24
27
 
25
28
  desc 'version', 'Prints Jirify version'
26
29
  def version
27
- puts "Current Jirify version: #{VERSION}"
30
+ say "Current Jirify version: #{VERSION}"
28
31
  end
29
32
 
30
33
  desc 'setup [SUBCOMMAND]', 'Jirify setup tools'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jirify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georgi Gardev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-07 00:00:00.000000000 Z
11
+ date: 2018-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.8.1
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.8.1
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: jira-ruby
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -45,6 +51,9 @@ dependencies:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
53
  version: '2.4'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.4.3
48
57
  type: :runtime
49
58
  prerelease: false
50
59
  version_requirements: !ruby/object:Gem::Requirement
@@ -52,6 +61,9 @@ dependencies:
52
61
  - - "~>"
53
62
  - !ruby/object:Gem::Version
54
63
  version: '2.4'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.4.3
55
67
  - !ruby/object:Gem::Dependency
56
68
  name: terminal-table
57
69
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +92,168 @@ dependencies:
80
92
  - - "~>"
81
93
  - !ruby/object:Gem::Version
82
94
  version: '0.20'
95
+ - !ruby/object:Gem::Dependency
96
+ name: coveralls
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.7'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 0.7.1
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.7'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 0.7.1
115
+ - !ruby/object:Gem::Dependency
116
+ name: guard
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '2.14'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 2.14.2
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.14'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 2.14.2
135
+ - !ruby/object:Gem::Dependency
136
+ name: guard-rspec
137
+ requirement: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: '4.7'
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 4.7.3
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '4.7'
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 4.7.3
155
+ - !ruby/object:Gem::Dependency
156
+ name: rake
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: '12.1'
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: '12.1'
169
+ - !ruby/object:Gem::Dependency
170
+ name: rake-release
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - "~>"
174
+ - !ruby/object:Gem::Version
175
+ version: '1.0'
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: 1.0.1
179
+ type: :development
180
+ prerelease: false
181
+ version_requirements: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: '1.0'
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: 1.0.1
189
+ - !ruby/object:Gem::Dependency
190
+ name: rspec
191
+ requirement: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: '3.7'
196
+ type: :development
197
+ prerelease: false
198
+ version_requirements: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - "~>"
201
+ - !ruby/object:Gem::Version
202
+ version: '3.7'
203
+ - !ruby/object:Gem::Dependency
204
+ name: rubocop
205
+ requirement: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: '0.57'
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: 0.57.2
213
+ type: :development
214
+ prerelease: false
215
+ version_requirements: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: '0.57'
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 0.57.2
223
+ - !ruby/object:Gem::Dependency
224
+ name: rubocop-rspec
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '1.27'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: '1.27'
237
+ - !ruby/object:Gem::Dependency
238
+ name: simplecov
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: '0.10'
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: 0.10.2
247
+ type: :development
248
+ prerelease: false
249
+ version_requirements: !ruby/object:Gem::Requirement
250
+ requirements:
251
+ - - "~>"
252
+ - !ruby/object:Gem::Version
253
+ version: '0.10'
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: 0.10.2
83
257
  description: JIRA for your terminal
84
258
  email: georgi@gardev.com
85
259
  executables:
@@ -103,12 +277,15 @@ files:
103
277
  - lib/jirify/models/status.rb
104
278
  - lib/jirify/models/transition_list.rb
105
279
  - lib/jirify/monkey_patches/jira_issue.rb
280
+ - lib/jirify/ui/sprint_cell.rb
281
+ - lib/jirify/ui/sprint_table.rb
106
282
  - lib/jirify/version.rb
107
283
  homepage: https://github.com/GeorgeSG/jirify
108
284
  licenses:
109
285
  - MIT
110
- metadata: {}
111
- post_install_message:
286
+ metadata:
287
+ source_code_uri: https://github.com/GeorgeSG/jirify
288
+ post_install_message: Thanks for installing! Run <jira setup> for initial configuration.
112
289
  rdoc_options: []
113
290
  require_paths:
114
291
  - lib