hustle_and_flow 0.0.1 → 0.0.2
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 +4 -4
- data/bin/hustle +5 -0
- data/lib/hustle_and_flow/binary/runner.rb +35 -0
- data/lib/hustle_and_flow/commands/start.rb +36 -0
- data/lib/hustle_and_flow/errors/unknown_issue_action_error.rb +6 -0
- data/lib/hustle_and_flow/formatters/branch_table_formatter.rb +81 -0
- data/lib/hustle_and_flow/formatters/issue_detail_formatter.rb +74 -0
- data/lib/hustle_and_flow/formatters/issue_table_formatter.rb +80 -0
- data/lib/hustle_and_flow/io/shell.rb +102 -0
- data/lib/hustle_and_flow/issue_tracker.rb +18 -0
- data/lib/hustle_and_flow/issue_trackers/github/issue.rb +192 -0
- data/lib/hustle_and_flow/issue_trackers/github/issues.rb +89 -0
- data/lib/hustle_and_flow/issue_trackers/github.rb +71 -0
- data/lib/hustle_and_flow/utils/string.rb +25 -0
- data/lib/hustle_and_flow/utils/url_slug.rb +28 -0
- data/lib/hustle_and_flow/vcs_repository.rb +19 -0
- data/lib/hustle_and_flow/version.rb +1 -1
- data/lib/hustle_and_flow/version_control/git/branch.rb +136 -0
- data/lib/hustle_and_flow/version_control/git/branches.rb +93 -0
- data/lib/hustle_and_flow/version_control/git/repository.rb +99 -0
- data/lib/hustle_and_flow.rb +1 -2
- data/spec/lib/hustle_and_flow/formatters/branch_table_formatter_spec.rb +44 -0
- data/spec/lib/hustle_and_flow/formatters/issue_detail_formatter_spec.rb +49 -0
- data/spec/lib/hustle_and_flow/formatters/issue_table_formatter_spec.rb +89 -0
- data/spec/lib/hustle_and_flow/io/shell_spec.rb +154 -0
- data/spec/lib/hustle_and_flow/issue_tracker_spec.rb +7 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github/issue_spec.rb +354 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github/issues_spec.rb +91 -0
- data/spec/lib/hustle_and_flow/issue_trackers/github_spec.rb +51 -0
- data/spec/lib/hustle_and_flow/vcs_repository_spec.rb +15 -0
- data/spec/lib/hustle_and_flow/version_control/git/branch_spec.rb +101 -0
- data/spec/lib/hustle_and_flow/version_control/git/branches_spec.rb +57 -0
- data/spec/lib/hustle_and_flow/version_control/git/repository_spec.rb +36 -0
- data/spec/lib/utils/url_slug_spec.rb +74 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/git_repo.rb +43 -0
- metadata +128 -16
- data/.gitignore +0 -19
- data/.ruby-version +0 -1
- data/.travis.yml +0 -13
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -56
- data/Rakefile +0 -2
- data/hustle_and_flow.gemspec +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 09c8b0e8909c7e772f202f9c4a8d5d51ef65423b
|
4
|
+
data.tar.gz: 29362f1b7e998396294e1925c69d939ba66dc2a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 623381f2772547914f6a2c26604542131eeec13d0c82351b0cd17e4bec7ba5c592ea646f0584f9cfb2032bda48ba839bb2f96d59ce435f2c1924f593ce4f95ba
|
7
|
+
data.tar.gz: 2f3f3906195c4043b503ab2939c8cc0625effb86badebf5c781a1cd6e928a5632bd18bb96ca0f1448f6aa062aadfca8c818811bb6d69bb24675b54a121a3e3fd
|
data/bin/hustle
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'hustle_and_flow/commands/start'
|
3
|
+
|
4
|
+
module HustleAndFlow
|
5
|
+
module Binary
|
6
|
+
class Runner < Thor
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
desc 'start', 'For generating new, or working on existing issues'
|
10
|
+
method_option :create,
|
11
|
+
type: :boolean,
|
12
|
+
aliases: '-c',
|
13
|
+
desc: 'Whether or not to create the issue if one cannot be found'
|
14
|
+
method_option :type,
|
15
|
+
type: :string,
|
16
|
+
aliases: '-t',
|
17
|
+
desc: 'The type of issue that should be searched for or created (eg feature, bug, chore, etc)'
|
18
|
+
method_option :status,
|
19
|
+
type: :string,
|
20
|
+
aliases: '-u',
|
21
|
+
desc: 'When searching for issues, it is the status of the issues you would like to view.'
|
22
|
+
method_option :subject,
|
23
|
+
type: :string,
|
24
|
+
aliases: '-s',
|
25
|
+
desc: 'The subject (or title) of the issue which should be searched for or created'
|
26
|
+
method_option :number,
|
27
|
+
type: :string,
|
28
|
+
aliases: '-n',
|
29
|
+
desc: 'The number of the issue which should be searched for.'
|
30
|
+
def start
|
31
|
+
Commands::Start.new(io: HustleAndFlow::Io::Shell.new, **options).call
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'thor/shell/basic'
|
2
|
+
require 'hustle_and_flow/vcs_repository'
|
3
|
+
require 'hustle_and_flow/issue_tracker'
|
4
|
+
|
5
|
+
module HustleAndFlow
|
6
|
+
module Commands
|
7
|
+
class Start
|
8
|
+
attr_accessor :repo,
|
9
|
+
:tracker,
|
10
|
+
:me,
|
11
|
+
:io,
|
12
|
+
:issue_data
|
13
|
+
|
14
|
+
def initialize(io:, **args)
|
15
|
+
self.repo = VcsRepository.new(path: Dir.pwd)
|
16
|
+
self.tracker = IssueTracker.new(repo: repo)
|
17
|
+
self.me = repo.user
|
18
|
+
self.io = io
|
19
|
+
self.issue_data = args.select { |_k, v| v }
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
issue = tracker.start(io: io,
|
24
|
+
me: me,
|
25
|
+
issue_data: issue_data)
|
26
|
+
_branch = repo.start(io: io,
|
27
|
+
number: issue.number,
|
28
|
+
title: issue.title,
|
29
|
+
branch_template: issue.to_branch_name(version: '*****'))
|
30
|
+
rescue Git::GitExecuteError => e
|
31
|
+
io.say 'There was a problem running a git command.'
|
32
|
+
io.say e.message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module HustleAndFlow
|
2
|
+
module Formatters
|
3
|
+
class BranchTableFormatter
|
4
|
+
attr_accessor :branches
|
5
|
+
|
6
|
+
def initialize(branches)
|
7
|
+
self.branches = branches
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_ary
|
11
|
+
number = 0
|
12
|
+
|
13
|
+
branches.map do |branch|
|
14
|
+
[
|
15
|
+
{
|
16
|
+
format: number_formatting(branch),
|
17
|
+
value: number += 1,
|
18
|
+
},
|
19
|
+
{
|
20
|
+
format: current_branch_formatting(branch),
|
21
|
+
value: branch.current? ? '*' : ' ',
|
22
|
+
},
|
23
|
+
{
|
24
|
+
format: status_formatting(branch),
|
25
|
+
value: status(branch),
|
26
|
+
},
|
27
|
+
{
|
28
|
+
format: author_formatting(branch),
|
29
|
+
value: branch.author,
|
30
|
+
},
|
31
|
+
{
|
32
|
+
format: name_formatting(branch),
|
33
|
+
value: branch.name,
|
34
|
+
},
|
35
|
+
]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def status(branch)
|
42
|
+
if branch.has_tracking_branch?
|
43
|
+
'T'
|
44
|
+
elsif branch.remote?
|
45
|
+
'R'
|
46
|
+
elsif branch.local?
|
47
|
+
'L'
|
48
|
+
else
|
49
|
+
'?'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def number_formatting(_branch)
|
54
|
+
[:white, :bold]
|
55
|
+
end
|
56
|
+
|
57
|
+
def name_formatting(_branch)
|
58
|
+
[:green, :bold]
|
59
|
+
end
|
60
|
+
|
61
|
+
def author_formatting(_branch)
|
62
|
+
[:white, :bold]
|
63
|
+
end
|
64
|
+
|
65
|
+
def current_branch_formatting(_branch)
|
66
|
+
[:yellow, :bold]
|
67
|
+
end
|
68
|
+
|
69
|
+
def status_formatting(branch)
|
70
|
+
case
|
71
|
+
when branch.has_tracking_branch?
|
72
|
+
[:yellow, :bold]
|
73
|
+
when branch.remote?
|
74
|
+
[:magenta, :bold]
|
75
|
+
when branch.local?
|
76
|
+
[:blue, :bold]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'hustle_and_flow/utils/string'
|
2
|
+
|
3
|
+
module HustleAndFlow
|
4
|
+
module Formatters
|
5
|
+
class IssueDetailFormatter
|
6
|
+
include HustleAndFlow::Utils::String
|
7
|
+
|
8
|
+
attr_accessor :issue
|
9
|
+
|
10
|
+
def initialize(issue)
|
11
|
+
self.issue = issue
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{
|
16
|
+
header: {
|
17
|
+
format: issue_header_formatting,
|
18
|
+
value: issue_header,
|
19
|
+
},
|
20
|
+
divider: {
|
21
|
+
format: issue_divider_formatting,
|
22
|
+
value: nil,
|
23
|
+
},
|
24
|
+
contact: {
|
25
|
+
format: issue_contact_formatting,
|
26
|
+
value: issue_contact,
|
27
|
+
},
|
28
|
+
body: {
|
29
|
+
format: issue_body_formatting,
|
30
|
+
value: issue.body,
|
31
|
+
},
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def issue_number
|
38
|
+
"##{issue.number}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def issue_header
|
42
|
+
category = if issue.category
|
43
|
+
"#{titleize(issue.category)}: "
|
44
|
+
end
|
45
|
+
|
46
|
+
"#{issue_number} - #{category}#{issue.title}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def issue_header_formatting
|
50
|
+
if issue.closed?
|
51
|
+
[:red, :bold]
|
52
|
+
else
|
53
|
+
[:green, :bold]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def issue_divider_formatting
|
58
|
+
[:black, :bold]
|
59
|
+
end
|
60
|
+
|
61
|
+
def issue_contact
|
62
|
+
"By: #{issue.contact}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def issue_contact_formatting
|
66
|
+
[:blue, :bold]
|
67
|
+
end
|
68
|
+
|
69
|
+
def issue_body_formatting
|
70
|
+
[:white, :bold]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'hustle_and_flow/utils/string'
|
2
|
+
|
3
|
+
module HustleAndFlow
|
4
|
+
module Formatters
|
5
|
+
class IssueTableFormatter
|
6
|
+
include HustleAndFlow::Utils::String
|
7
|
+
|
8
|
+
attr_accessor :issues,
|
9
|
+
:title
|
10
|
+
|
11
|
+
def initialize(issues)
|
12
|
+
self.issues = issues
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_ary
|
16
|
+
issues.map do |issue|
|
17
|
+
[
|
18
|
+
{
|
19
|
+
format: number_formatting(issue),
|
20
|
+
value: "##{issue.number}",
|
21
|
+
},
|
22
|
+
{
|
23
|
+
format: contact_formatting(issue),
|
24
|
+
value: issue.contact,
|
25
|
+
},
|
26
|
+
{
|
27
|
+
format: category_formatting(issue),
|
28
|
+
value: titleize(issue.category),
|
29
|
+
},
|
30
|
+
{
|
31
|
+
format: title_formatting(issue),
|
32
|
+
value: issue.title,
|
33
|
+
},
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def number_formatting(issue)
|
41
|
+
if issue.closed?
|
42
|
+
[:red]
|
43
|
+
else
|
44
|
+
[:green]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def contact_formatting(_issue)
|
49
|
+
[:white]
|
50
|
+
end
|
51
|
+
|
52
|
+
def category_formatting(issue)
|
53
|
+
case issue.category
|
54
|
+
when 'feature'
|
55
|
+
[:green, :bold]
|
56
|
+
when 'bug'
|
57
|
+
[:red, :bold]
|
58
|
+
when 'refactor'
|
59
|
+
[:yellow, :bold]
|
60
|
+
when 'test'
|
61
|
+
[:cyan, :bold]
|
62
|
+
when 'style'
|
63
|
+
[:magenta, :bold]
|
64
|
+
when 'chore'
|
65
|
+
[:white, :bold]
|
66
|
+
when 'docs'
|
67
|
+
[:blue, :bold]
|
68
|
+
when 'spike'
|
69
|
+
[:white, :bold]
|
70
|
+
else
|
71
|
+
[:white, :bold]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def title_formatting(_issue)
|
76
|
+
[:white]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'thor/shell/color'
|
2
|
+
require 'hustle_and_flow/formatters/issue_detail_formatter'
|
3
|
+
|
4
|
+
module HustleAndFlow
|
5
|
+
module Io
|
6
|
+
class Shell < Thor::Shell::Color
|
7
|
+
def correct_issue?(issue)
|
8
|
+
if issue.new?
|
9
|
+
Kernel.system("open #{issue.url}")
|
10
|
+
else
|
11
|
+
stdout.puts
|
12
|
+
print_issue Formatters::IssueDetailFormatter.new(issue).to_hash
|
13
|
+
|
14
|
+
yes?('Does this issue look correct?')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def reassign_issue?(from:)
|
19
|
+
yes?("Do you want to reassign this issue from #{from} to yourself?")
|
20
|
+
end
|
21
|
+
|
22
|
+
def choose_issue
|
23
|
+
stdout.puts
|
24
|
+
|
25
|
+
ask 'Enter the number of the issue you would like to work on:'
|
26
|
+
end
|
27
|
+
|
28
|
+
def choose_branch
|
29
|
+
stdout.puts
|
30
|
+
ask 'Enter the number of the branch you would like to work on:'
|
31
|
+
end
|
32
|
+
|
33
|
+
def print_new_branch_prompt(new_branch_name)
|
34
|
+
stdout.puts
|
35
|
+
say "Entering 'c' creates a new branch named '#{GREEN}#{new_branch_name}#{CLEAR}'"
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_formatted_table(data:, title: nil)
|
39
|
+
data = data.map do |row|
|
40
|
+
row.map do |column|
|
41
|
+
set_color(column[:value], *column[:format])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
stdout.puts
|
46
|
+
|
47
|
+
if title
|
48
|
+
stdout.puts title.center(terminal_width)
|
49
|
+
stdout.puts '-' * terminal_width
|
50
|
+
end
|
51
|
+
|
52
|
+
print_table(data, truncate: true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def print_issue(data)
|
56
|
+
data[:header][:format].each do |format|
|
57
|
+
stdout.print lookup_color(format)
|
58
|
+
end
|
59
|
+
|
60
|
+
print_wrapped(data[:header][:value])
|
61
|
+
|
62
|
+
stdout.puts set_color('-' * terminal_width, *data[:divider][:format])
|
63
|
+
stdout.puts set_color(data[:contact][:value], *data[:contact][:format])
|
64
|
+
|
65
|
+
data[:body][:format].each do |format|
|
66
|
+
stdout.print lookup_color(format)
|
67
|
+
end
|
68
|
+
|
69
|
+
if data[:body][:value]
|
70
|
+
stdout.puts
|
71
|
+
print_wrapped(data[:body][:value])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# To be removed once our PR lands
|
76
|
+
def print_wrapped(message, options = {})
|
77
|
+
indent = options[:indent] || 0
|
78
|
+
width = 80
|
79
|
+
paras = message.split("\n\n")
|
80
|
+
|
81
|
+
paras.map! do |unwrapped|
|
82
|
+
unwrapped.
|
83
|
+
strip.
|
84
|
+
gsub(/\n/, ' ').
|
85
|
+
squeeze(' ').
|
86
|
+
gsub(/.{1,#{width}}(?:\s|\Z)/) do
|
87
|
+
($& + 5.chr).
|
88
|
+
gsub(/\n\005/, "\n").
|
89
|
+
gsub(/\005/, "\n")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
paras.each do |para|
|
94
|
+
para.split("\n").each do |line|
|
95
|
+
stdout.puts line.insert(0, ' ' * indent)
|
96
|
+
end
|
97
|
+
stdout.puts unless para == paras.last
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'hustle_and_flow/issue_trackers/github'
|
2
|
+
|
3
|
+
module HustleAndFlow
|
4
|
+
class IssueTracker
|
5
|
+
attr_accessor :adapter
|
6
|
+
|
7
|
+
def initialize(**args)
|
8
|
+
self.adapter = HustleAndFlow::
|
9
|
+
IssueTrackers::
|
10
|
+
Github.
|
11
|
+
new(repo: args[:repo])
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(name, *args)
|
15
|
+
adapter.public_send(name, *args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'hustle_and_flow/utils/url_slug'
|
2
|
+
require 'hustle_and_flow/errors/unknown_issue_action_error'
|
3
|
+
require 'hustle_and_flow/io/shell'
|
4
|
+
|
5
|
+
module HustleAndFlow
|
6
|
+
module IssueTrackers
|
7
|
+
class Github
|
8
|
+
class Issue
|
9
|
+
DEFAULT_CATEGORY_LABELS = %w{feature bug refactor test style chore docs spike}
|
10
|
+
ISSUE_ACTIONS = %w{closes references fixes}
|
11
|
+
|
12
|
+
attr_accessor :tracker,
|
13
|
+
:io,
|
14
|
+
:data
|
15
|
+
|
16
|
+
def initialize(tracker:, io: nil, data:)
|
17
|
+
self.tracker = tracker
|
18
|
+
self.io = io || HustleAndFlow::Io::Shell.new
|
19
|
+
self.data = data
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.create(tracker: nil, io: nil, title:, body: '', **args)
|
23
|
+
new(io: io,
|
24
|
+
tracker: tracker,
|
25
|
+
data: tracker.client.create_issue(tracker.repo_name,
|
26
|
+
title,
|
27
|
+
body,
|
28
|
+
**args))
|
29
|
+
end
|
30
|
+
|
31
|
+
def start(me: nil)
|
32
|
+
return unless io.correct_issue?(self)
|
33
|
+
|
34
|
+
reopen.
|
35
|
+
assign_issue? to: me
|
36
|
+
end
|
37
|
+
|
38
|
+
def assign(to:)
|
39
|
+
reassigned_issue_data = client.update_issue(tracker.repo_name,
|
40
|
+
number,
|
41
|
+
title,
|
42
|
+
body,
|
43
|
+
assignee: to)
|
44
|
+
|
45
|
+
Issue.new(tracker: tracker,
|
46
|
+
data: reassigned_issue_data)
|
47
|
+
end
|
48
|
+
|
49
|
+
def category
|
50
|
+
@category ||= labels.find do |label|
|
51
|
+
DEFAULT_CATEGORY_LABELS.include? label
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def new?
|
56
|
+
five_minutes_ago = Time.now.utc - (5 * 60)
|
57
|
+
|
58
|
+
five_minutes_ago <= created_at
|
59
|
+
end
|
60
|
+
|
61
|
+
def has_label?(other)
|
62
|
+
labels.include?(other)
|
63
|
+
end
|
64
|
+
|
65
|
+
def has_body?
|
66
|
+
!(body.nil? || body.empty?)
|
67
|
+
end
|
68
|
+
|
69
|
+
def assign_issue?(to:)
|
70
|
+
return self unless needs_reassignment?(assignee_to_assign_to: to)
|
71
|
+
|
72
|
+
assign to: to
|
73
|
+
end
|
74
|
+
|
75
|
+
def closed?
|
76
|
+
status == 'closed'
|
77
|
+
end
|
78
|
+
|
79
|
+
def unassigned?
|
80
|
+
assigned_to? 'unassigned'
|
81
|
+
end
|
82
|
+
|
83
|
+
def assigned_to?(other)
|
84
|
+
assignee == other
|
85
|
+
end
|
86
|
+
|
87
|
+
def match?(type: nil, **args)
|
88
|
+
result = true
|
89
|
+
conditions = args
|
90
|
+
|
91
|
+
conditions.each do |key, value|
|
92
|
+
result &&= public_send(key) == value
|
93
|
+
end
|
94
|
+
|
95
|
+
type ? (result && has_label?(type)) : result
|
96
|
+
end
|
97
|
+
|
98
|
+
def contact
|
99
|
+
assignee_data[:login] || user_data[:login]
|
100
|
+
end
|
101
|
+
|
102
|
+
def title
|
103
|
+
data[:title]
|
104
|
+
end
|
105
|
+
|
106
|
+
def number
|
107
|
+
data[:number]
|
108
|
+
end
|
109
|
+
|
110
|
+
def body
|
111
|
+
data[:body]
|
112
|
+
end
|
113
|
+
|
114
|
+
def created_at
|
115
|
+
data[:created_at]
|
116
|
+
end
|
117
|
+
|
118
|
+
def url
|
119
|
+
data[:html_url]
|
120
|
+
end
|
121
|
+
|
122
|
+
def status
|
123
|
+
data[:state]
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_branch_name(action: 'closes',
|
127
|
+
version: 1)
|
128
|
+
branch_name = []
|
129
|
+
branch_name << category
|
130
|
+
branch_name << base_branch_name(action: action,
|
131
|
+
version: version)
|
132
|
+
|
133
|
+
branch_name.compact!
|
134
|
+
|
135
|
+
branch_name.join('/')
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def reopen
|
141
|
+
reopened_issue_data = client.reopen_issue(tracker.repo_name, number)
|
142
|
+
|
143
|
+
closed? ? Issue.new(tracker: tracker, data: reopened_issue_data) : self
|
144
|
+
end
|
145
|
+
|
146
|
+
def labels
|
147
|
+
return [] unless data[:labels]
|
148
|
+
|
149
|
+
@labels ||= data[:labels].map { |l| l[:name] }
|
150
|
+
end
|
151
|
+
|
152
|
+
def assignee
|
153
|
+
assignee_data[:login] || 'unassigned'
|
154
|
+
end
|
155
|
+
|
156
|
+
def assignee_data
|
157
|
+
data[:assignee] || {}
|
158
|
+
end
|
159
|
+
|
160
|
+
def user_data
|
161
|
+
data[:user] || {}
|
162
|
+
end
|
163
|
+
|
164
|
+
def client
|
165
|
+
tracker.client
|
166
|
+
end
|
167
|
+
|
168
|
+
def needs_reassignment?(assignee_to_assign_to:)
|
169
|
+
unassigned? ||
|
170
|
+
(
|
171
|
+
!assigned_to?(assignee_to_assign_to) &&
|
172
|
+
io.reassign_issue?(from: assignee)
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
def base_branch_name(action:, version:)
|
177
|
+
fail Errors::UnknownIssueActionError unless ISSUE_ACTIONS.include? action.downcase
|
178
|
+
|
179
|
+
base = []
|
180
|
+
base << Utils::UrlSlug.new(title).to_s
|
181
|
+
base << action if number
|
182
|
+
base << number
|
183
|
+
base << "v#{version}" if version
|
184
|
+
|
185
|
+
base.compact!
|
186
|
+
|
187
|
+
base.join('-').downcase
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|