geet 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +25 -24
- data/bin/geet +21 -3
- data/geet.gemspec +2 -2
- data/lib/geet/commandline/configuration.rb +5 -5
- data/lib/geet/git/repository.rb +34 -15
- data/lib/geet/services/abstract_create_issue.rb +33 -0
- data/lib/geet/services/create_gist.rb +6 -4
- data/lib/geet/services/create_issue.rb +33 -87
- data/lib/geet/services/create_label.rb +7 -6
- data/lib/geet/services/create_pr.rb +42 -86
- data/lib/geet/services/list_issues.rb +13 -14
- data/lib/geet/services/list_labels.rb +4 -3
- data/lib/geet/services/list_milestones.rb +12 -11
- data/lib/geet/services/list_prs.rb +4 -3
- data/lib/geet/services/merge_pr.rb +12 -11
- data/lib/geet/shared/constants.rb +9 -0
- data/lib/geet/utils/attributes_selection_manager.rb +87 -0
- data/lib/geet/utils/manual_list_selection.rb +41 -27
- data/lib/geet/utils/string_matching_selection.rb +32 -0
- data/lib/geet/version.rb +1 -1
- data/spec/integration/create_gist_spec.rb +4 -4
- data/spec/integration/create_issue_spec.rb +6 -6
- data/spec/integration/create_label_spec.rb +3 -3
- data/spec/integration/create_pr_spec.rb +13 -13
- data/spec/integration/list_issues_spec.rb +5 -5
- data/spec/integration/list_labels_spec.rb +3 -3
- data/spec/integration/list_milestones_spec.rb +2 -2
- data/spec/integration/list_prs_spec.rb +2 -2
- data/spec/integration/merge_pr_spec.rb +2 -2
- data/spec/vcr_cassettes/create_issue_upstream.yml +1 -1
- data/spec/vcr_cassettes/create_pr.yml +181 -102
- data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +1 -1
- data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +1 -1
- data/spec/vcr_cassettes/create_pr_upstream.yml +2 -2
- metadata +8 -5
- data/lib/geet/utils/pattern_matching_selection.rb +0 -27
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'manual_list_selection'
|
4
|
+
require_relative 'string_matching_selection'
|
5
|
+
require_relative '../shared/constants'
|
6
|
+
|
7
|
+
module Geet
|
8
|
+
module Utils
|
9
|
+
# Manages the retrieval and selection of attributes.
|
10
|
+
#
|
11
|
+
# Selecting an attribute happens in two steps: retrieval and selection.
|
12
|
+
#
|
13
|
+
# With this structure, the retrieval happens in parallel, cutting the time considerably when
|
14
|
+
# multiple attributes are required (typically, three).
|
15
|
+
#
|
16
|
+
class AttributesSelectionManager
|
17
|
+
include Geet::Shared::Constants
|
18
|
+
|
19
|
+
# Initialize the instance, and starts the background threads.
|
20
|
+
#
|
21
|
+
def initialize(repository, out: output)
|
22
|
+
@repository = repository
|
23
|
+
@out = out
|
24
|
+
@selections_data = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_attribute(repository_call, description, pattern, selection_type, name_method: nil, &pre_selection_hook)
|
28
|
+
raise "Unrecognized selection type #{selection_type.inspect}" if ![:single, :multiple].include?(selection_type)
|
29
|
+
|
30
|
+
finder_thread = find_attribute_entries(repository_call)
|
31
|
+
|
32
|
+
@selections_data << [finder_thread, description, pattern, selection_type, name_method, pre_selection_hook]
|
33
|
+
end
|
34
|
+
|
35
|
+
# Select and return the attributes, in the same order they've been added.
|
36
|
+
#
|
37
|
+
def select_attributes
|
38
|
+
@selections_data.map do |finder_thread, description, pattern, selection_type, name_method, pre_selection_hook|
|
39
|
+
entries = finder_thread.value
|
40
|
+
|
41
|
+
entries = pre_selection_hook.(entries) if pre_selection_hook
|
42
|
+
|
43
|
+
case selection_type
|
44
|
+
when :single
|
45
|
+
select_entry(description, entries, pattern, name_method)
|
46
|
+
when :multiple
|
47
|
+
select_entries(description, entries, pattern, name_method)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def find_attribute_entries(repository_call)
|
55
|
+
@out.puts "Finding #{repository_call}..."
|
56
|
+
|
57
|
+
Thread.new do
|
58
|
+
@repository.send(repository_call)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sample call:
|
63
|
+
#
|
64
|
+
# select_entry('milestone', all_milestones, '0.1.0', :title)
|
65
|
+
#
|
66
|
+
def select_entry(entry_type, entries, pattern, name_method)
|
67
|
+
if pattern == MANUAL_LIST_SELECTION_FLAG
|
68
|
+
Geet::Utils::ManualListSelection.new.select_entry(entry_type, entries, name_method: name_method)
|
69
|
+
else
|
70
|
+
Geet::Utils::StringMatchingSelection.new.select_entry(entry_type, entries, pattern, name_method: name_method)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sample call:
|
75
|
+
#
|
76
|
+
# select_entries('reviewer', all_collaborators, 'donaldduck', nil)
|
77
|
+
#
|
78
|
+
def select_entries(entry_type, entries, pattern, name_method)
|
79
|
+
if pattern == MANUAL_LIST_SELECTION_FLAG
|
80
|
+
Geet::Utils::ManualListSelection.new.select_entries(entry_type, entries, name_method: name_method)
|
81
|
+
else
|
82
|
+
Geet::Utils::StringMatchingSelection.new.select_entries(entry_type, entries, pattern, name_method: name_method)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -9,56 +9,70 @@ module Geet
|
|
9
9
|
|
10
10
|
PAGER_SIZE = 16
|
11
11
|
|
12
|
+
# Shows a prompt for selecting an entry from a list.
|
13
|
+
#
|
14
|
+
# Returns nil, without showing the prompt, if there are no entries.
|
15
|
+
#
|
12
16
|
# entry_type: description of the entries type.
|
13
|
-
# entries: array of objects; if they're not strings, must also pass :
|
17
|
+
# entries: array of objects; if they're not strings, must also pass :name_method.
|
14
18
|
# this value must not be empty.
|
15
|
-
#
|
16
|
-
# instance_method: required when non-string objects are passed as entries; its invocation on
|
19
|
+
# name_method: required when non-string objects are passed as entries; its invocation on
|
17
20
|
# each object must return a string, which is used as key.
|
18
21
|
#
|
19
|
-
# returns: the selected entry
|
20
|
-
#
|
22
|
+
# returns: the selected entry. if no entries are nil is returned.
|
23
|
+
#
|
24
|
+
def select_entry(entry_type, entries, name_method: nil)
|
25
|
+
return nil if entries.empty?
|
26
|
+
|
27
|
+
check_entries(entries, entry_type)
|
28
|
+
|
29
|
+
entries = create_entries_map(entries, name_method)
|
30
|
+
entries = add_no_selection_entry(entries)
|
31
|
+
|
32
|
+
show_prompt(:select, entry_type, entries)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Shows a prompt for selecting an entry from a list.
|
36
|
+
#
|
37
|
+
# Returns an empty array, without showing the prompt, if there are no entries.
|
38
|
+
#
|
39
|
+
# See #select_entry for the parameters.
|
21
40
|
#
|
22
|
-
|
23
|
-
|
41
|
+
# returns: array of entries.
|
42
|
+
#
|
43
|
+
def select_entries(entry_type, entries, name_method: nil)
|
44
|
+
return [] if entries.empty?
|
24
45
|
|
25
|
-
|
46
|
+
check_entries(entries, entry_type)
|
26
47
|
|
27
|
-
|
48
|
+
entries = create_entries_map(entries, name_method)
|
28
49
|
|
29
|
-
|
50
|
+
show_prompt(:multi_select, entry_type, entries)
|
30
51
|
end
|
31
52
|
|
32
53
|
private
|
33
54
|
|
34
|
-
def check_entries(entries)
|
55
|
+
def check_entries(entries, entry_type)
|
35
56
|
raise "No #{entry_type} provided!" if entries.empty?
|
36
57
|
end
|
37
58
|
|
38
|
-
def create_entries_map(entries,
|
59
|
+
def create_entries_map(entries, name_method)
|
39
60
|
entries.each_with_object({}) do |entry, current_map|
|
40
|
-
key =
|
61
|
+
key = name_method ? entry.send(name_method) : entry
|
41
62
|
current_map[key] = entry
|
42
63
|
end
|
43
64
|
end
|
44
65
|
|
45
|
-
def show_prompt(entry_type, selection_type, entries)
|
46
|
-
prompt_title = "Please select the #{entry_type}(s):"
|
47
|
-
|
48
|
-
case selection_type
|
49
|
-
when :single
|
50
|
-
entries = add_no_selection_entry(entries)
|
51
|
-
TTY::Prompt.new.select(prompt_title, entries, filter: true, per_page: PAGER_SIZE)
|
52
|
-
when :multiple
|
53
|
-
TTY::Prompt.new.multi_select(prompt_title, entries, filter: true, per_page: PAGER_SIZE)
|
54
|
-
else
|
55
|
-
raise "Unexpected selection type: #{selection_type.inspect}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
66
|
def add_no_selection_entry(entries)
|
60
67
|
{NO_SELECTION_KEY => nil}.merge(entries)
|
61
68
|
end
|
69
|
+
|
70
|
+
def show_prompt(invocation_method, entry_type, entries)
|
71
|
+
# Arguably inexact phrasing for avoiding language complexities.
|
72
|
+
prompt_title = "Please select the #{entry_type}(s):"
|
73
|
+
|
74
|
+
TTY::Prompt.new.send(invocation_method, prompt_title, entries, filter: true, per_page: PAGER_SIZE)
|
75
|
+
end
|
62
76
|
end
|
63
77
|
end
|
64
78
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Geet
|
4
|
+
module Utils
|
5
|
+
class StringMatchingSelection
|
6
|
+
def select_entry(entry_type, entries, pattern, name_method: nil)
|
7
|
+
entries_found = entries.select do |entry|
|
8
|
+
entry = entry.send(name_method) if name_method
|
9
|
+
entry.downcase == pattern.downcase
|
10
|
+
end
|
11
|
+
|
12
|
+
case entries_found.size
|
13
|
+
when 1
|
14
|
+
entries_found.first
|
15
|
+
when 0
|
16
|
+
raise "No entry found for #{entry_type} pattern: #{pattern.inspect}"
|
17
|
+
else
|
18
|
+
raise "Multiple entries found for #{entry_type} pattern #{pattern.inspect}: #{entries_found}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def select_entries(entry_type, entries, raw_patterns, name_method: nil)
|
23
|
+
patterns = raw_patterns.split(',')
|
24
|
+
|
25
|
+
patterns.map do |pattern|
|
26
|
+
# Haha.
|
27
|
+
select_entry(entry_type, entries, pattern, name_method: name_method)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/geet/version.rb
CHANGED
@@ -18,8 +18,8 @@ describe Geet::Services::CreateGist do
|
|
18
18
|
actual_output = StringIO.new
|
19
19
|
|
20
20
|
VCR.use_cassette('create_gist_public') do
|
21
|
-
described_class.new.execute(
|
22
|
-
tempfile.path, description: 'testdescription', publik: true, no_browse: true
|
21
|
+
described_class.new(out: actual_output).execute(
|
22
|
+
tempfile.path, description: 'testdescription', publik: true, no_browse: true
|
23
23
|
)
|
24
24
|
end
|
25
25
|
|
@@ -35,8 +35,8 @@ describe Geet::Services::CreateGist do
|
|
35
35
|
actual_output = StringIO.new
|
36
36
|
|
37
37
|
VCR.use_cassette('create_gist_private') do
|
38
|
-
described_class.new.execute(
|
39
|
-
tempfile.path, description: 'testdescription', no_browse: true
|
38
|
+
described_class.new(out: actual_output).execute(
|
39
|
+
tempfile.path, description: 'testdescription', no_browse: true
|
40
40
|
)
|
41
41
|
end
|
42
42
|
|
@@ -16,7 +16,7 @@ describe Geet::Services::CreateIssue do
|
|
16
16
|
|
17
17
|
expected_output = <<~STR
|
18
18
|
Finding labels...
|
19
|
-
Finding
|
19
|
+
Finding milestones...
|
20
20
|
Finding collaborators...
|
21
21
|
Creating the issue...
|
22
22
|
Adding labels bug, invalid...
|
@@ -28,10 +28,10 @@ describe Geet::Services::CreateIssue do
|
|
28
28
|
actual_output = StringIO.new
|
29
29
|
|
30
30
|
actual_created_issue = VCR.use_cassette('create_issue') do
|
31
|
-
described_class.new(repository).execute(
|
31
|
+
described_class.new(repository, out: actual_output).execute(
|
32
32
|
'Title', 'Description',
|
33
|
-
|
34
|
-
no_open_issue: true
|
33
|
+
labels: 'bug,invalid', milestone: '0.0.1', assignees: 'donald-ts,donald-fr',
|
34
|
+
no_open_issue: true
|
35
35
|
)
|
36
36
|
end
|
37
37
|
|
@@ -56,8 +56,8 @@ describe Geet::Services::CreateIssue do
|
|
56
56
|
actual_output = StringIO.new
|
57
57
|
|
58
58
|
actual_created_issue = VCR.use_cassette('create_issue_upstream') do
|
59
|
-
create_options = { no_open_issue: true,
|
60
|
-
described_class.new(upstream_repository).execute('Title', 'Description', create_options)
|
59
|
+
create_options = { no_open_issue: true, out: actual_output }
|
60
|
+
described_class.new(upstream_repository, out: actual_output).execute('Title', 'Description', create_options)
|
61
61
|
end
|
62
62
|
|
63
63
|
expect(actual_output.string).to eql(expected_output)
|
@@ -22,7 +22,7 @@ describe Geet::Services::CreateLabel do
|
|
22
22
|
actual_output = StringIO.new
|
23
23
|
|
24
24
|
actual_created_label = VCR.use_cassette('create_label') do
|
25
|
-
described_class.new(repository).execute('my_label', color: 'c64c64'
|
25
|
+
described_class.new(repository, out: actual_output).execute('my_label', color: 'c64c64')
|
26
26
|
end
|
27
27
|
|
28
28
|
expect(actual_output.string).to eql(expected_output)
|
@@ -44,7 +44,7 @@ describe Geet::Services::CreateLabel do
|
|
44
44
|
actual_output = StringIO.new
|
45
45
|
|
46
46
|
actual_created_label = VCR.use_cassette('create_label_upstream') do
|
47
|
-
described_class.new(upstream_repository).execute('my_label', color: 'c64c64'
|
47
|
+
described_class.new(upstream_repository, out: actual_output).execute('my_label', color: 'c64c64')
|
48
48
|
end
|
49
49
|
|
50
50
|
expect(actual_output.string).to eql(expected_output)
|
@@ -67,7 +67,7 @@ describe Geet::Services::CreateLabel do
|
|
67
67
|
actual_output = StringIO.new
|
68
68
|
|
69
69
|
actual_created_label = VCR.use_cassette('create_label_with_random_color') do
|
70
|
-
described_class.new(repository).execute('my_label'
|
70
|
+
described_class.new(repository, out: actual_output).execute('my_label')
|
71
71
|
end
|
72
72
|
|
73
73
|
expected_output = format(expected_output_template, color: actual_created_label.color)
|
@@ -17,32 +17,32 @@ describe Geet::Services::CreatePr do
|
|
17
17
|
|
18
18
|
expected_output = <<~STR
|
19
19
|
Finding labels...
|
20
|
-
Finding
|
20
|
+
Finding milestones...
|
21
21
|
Finding collaborators...
|
22
22
|
Creating PR...
|
23
23
|
Assigning authenticated user...
|
24
|
-
Adding labels
|
25
|
-
Setting milestone
|
26
|
-
Requesting review from donald-
|
27
|
-
PR address: https://github.com/donaldduck/testrepo/pull/
|
24
|
+
Adding labels bug, invalid...
|
25
|
+
Setting milestone milestone 1...
|
26
|
+
Requesting review from donald-fr...
|
27
|
+
PR address: https://github.com/donaldduck/testrepo/pull/39
|
28
28
|
STR
|
29
29
|
|
30
30
|
actual_output = StringIO.new
|
31
31
|
|
32
32
|
actual_created_pr = VCR.use_cassette('create_pr') do
|
33
|
-
service_instance = described_class.new(repository, git_client: git_client)
|
33
|
+
service_instance = described_class.new(repository, out: actual_output, git_client: git_client)
|
34
34
|
service_instance.execute(
|
35
35
|
'Title', 'Description',
|
36
|
-
|
36
|
+
labels: 'bug,invalid', milestone: 'milestone 1', reviewers: 'donald-fr',
|
37
37
|
no_open_pr: true, output: actual_output
|
38
38
|
)
|
39
39
|
end
|
40
40
|
|
41
41
|
expect(actual_output.string).to eql(expected_output)
|
42
42
|
|
43
|
-
expect(actual_created_pr.number).to eql(
|
43
|
+
expect(actual_created_pr.number).to eql(39)
|
44
44
|
expect(actual_created_pr.title).to eql('Title')
|
45
|
-
expect(actual_created_pr.link).to eql('https://github.com/donaldduck/testrepo/pull/
|
45
|
+
expect(actual_created_pr.link).to eql('https://github.com/donaldduck/testrepo/pull/39')
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -60,7 +60,7 @@ describe Geet::Services::CreatePr do
|
|
60
60
|
actual_output = StringIO.new
|
61
61
|
|
62
62
|
actual_created_pr = VCR.use_cassette('create_pr_upstream') do
|
63
|
-
service_instance = described_class.new(upstream_repository, git_client: git_client)
|
63
|
+
service_instance = described_class.new(upstream_repository, out: actual_output, git_client: git_client)
|
64
64
|
service_instance.execute('Title', 'Description', no_open_pr: true, output: actual_output)
|
65
65
|
end
|
66
66
|
|
@@ -83,7 +83,7 @@ describe Geet::Services::CreatePr do
|
|
83
83
|
actual_output = StringIO.new
|
84
84
|
|
85
85
|
operation = -> do
|
86
|
-
service_instance = described_class.new(repository, git_client: git_client)
|
86
|
+
service_instance = described_class.new(repository, out: actual_output, git_client: git_client)
|
87
87
|
service_instance.execute('Title', 'Description', output: actual_output, automated_mode: true, no_open_pr: true)
|
88
88
|
end
|
89
89
|
|
@@ -110,7 +110,7 @@ describe Geet::Services::CreatePr do
|
|
110
110
|
actual_output = StringIO.new
|
111
111
|
|
112
112
|
actual_created_pr = VCR.use_cassette('create_pr_in_auto_mode_with_push') do
|
113
|
-
service_instance = described_class.new(repository, git_client: git_client)
|
113
|
+
service_instance = described_class.new(repository, out: actual_output, git_client: git_client)
|
114
114
|
service_instance.execute('Title', 'Description', output: actual_output, automated_mode: true, no_open_pr: true)
|
115
115
|
end
|
116
116
|
|
@@ -135,7 +135,7 @@ describe Geet::Services::CreatePr do
|
|
135
135
|
actual_output = StringIO.new
|
136
136
|
|
137
137
|
actual_created_pr = VCR.use_cassette('create_pr_in_auto_mode_create_upstream') do
|
138
|
-
service_instance = described_class.new(repository, git_client: git_client)
|
138
|
+
service_instance = described_class.new(repository, out: actual_output, git_client: git_client)
|
139
139
|
service_instance.execute('Title', 'Description', output: actual_output, automated_mode: true, no_open_pr: true)
|
140
140
|
end
|
141
141
|
|
@@ -23,7 +23,7 @@ describe Geet::Services::ListIssues do
|
|
23
23
|
actual_output = StringIO.new
|
24
24
|
|
25
25
|
service_result = VCR.use_cassette('github_com/list_issues') do
|
26
|
-
described_class.new(repository
|
26
|
+
described_class.new(repository, out: actual_output).execute
|
27
27
|
end
|
28
28
|
|
29
29
|
actual_issue_numbers = service_result.map(&:number)
|
@@ -37,7 +37,7 @@ describe Geet::Services::ListIssues do
|
|
37
37
|
allow(git_client).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo_gh')
|
38
38
|
|
39
39
|
expected_output = <<~STR
|
40
|
-
Finding
|
40
|
+
Finding collaborators...
|
41
41
|
12. test issue 3 (https://github.com/donaldduck/testrepo_gh/issues/12)
|
42
42
|
10. test issue 1 (https://github.com/donaldduck/testrepo_gh/issues/10)
|
43
43
|
STR
|
@@ -46,7 +46,7 @@ describe Geet::Services::ListIssues do
|
|
46
46
|
actual_output = StringIO.new
|
47
47
|
|
48
48
|
service_result = VCR.use_cassette('github_com/list_issues_with_assignee') do
|
49
|
-
described_class.new(repository).execute(
|
49
|
+
described_class.new(repository, out: actual_output).execute(assignee: 'donald-fr', )
|
50
50
|
end
|
51
51
|
|
52
52
|
actual_issue_numbers = service_result.map(&:number)
|
@@ -69,7 +69,7 @@ describe Geet::Services::ListIssues do
|
|
69
69
|
actual_output = StringIO.new
|
70
70
|
|
71
71
|
service_result = VCR.use_cassette('github_com/list_issues_upstream') do
|
72
|
-
described_class.new(upstream_repository
|
72
|
+
described_class.new(upstream_repository, out: actual_output).execute
|
73
73
|
end
|
74
74
|
|
75
75
|
actual_issue_numbers = service_result.map(&:number)
|
@@ -92,7 +92,7 @@ describe Geet::Services::ListIssues do
|
|
92
92
|
actual_output = StringIO.new
|
93
93
|
|
94
94
|
service_result = VCR.use_cassette('gitlab_com/list_issues') do
|
95
|
-
described_class.new(repository
|
95
|
+
described_class.new(repository, out: actual_output).execute
|
96
96
|
end
|
97
97
|
|
98
98
|
actual_issue_numbers = service_result.map(&:number)
|
@@ -24,7 +24,7 @@ describe Geet::Services::ListLabels do
|
|
24
24
|
|
25
25
|
actual_output = StringIO.new
|
26
26
|
actual_labels = VCR.use_cassette('github.com/list_labels') do
|
27
|
-
described_class.new(repository
|
27
|
+
described_class.new(repository, out: actual_output).execute
|
28
28
|
end
|
29
29
|
|
30
30
|
actual_label_names = actual_labels.map(&:name)
|
@@ -45,7 +45,7 @@ describe Geet::Services::ListLabels do
|
|
45
45
|
|
46
46
|
actual_output = StringIO.new
|
47
47
|
actual_labels = VCR.use_cassette('github.com/list_labels_upstream') do
|
48
|
-
described_class.new(upstream_repository
|
48
|
+
described_class.new(upstream_repository, out: actual_output).execute
|
49
49
|
end
|
50
50
|
|
51
51
|
actual_label_names = actual_labels.map(&:name)
|
@@ -73,7 +73,7 @@ describe Geet::Services::ListLabels do
|
|
73
73
|
|
74
74
|
actual_output = StringIO.new
|
75
75
|
actual_labels = VCR.use_cassette('gitlab.com/list_labels') do
|
76
|
-
described_class.new(repository
|
76
|
+
described_class.new(repository, out: actual_output).execute
|
77
77
|
end
|
78
78
|
|
79
79
|
actual_label_names = actual_labels.map(&:name)
|