geet 0.3.0 → 0.3.1
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/Gemfile +6 -10
- data/Gemfile.lock +8 -2
- data/README.md +27 -2
- data/Rakefile +3 -1
- data/bin/geet +37 -17
- data/geet.gemspec +3 -1
- data/lib/geet/commandline/configuration.rb +18 -5
- data/lib/geet/commandline/editor.rb +14 -24
- data/lib/geet/git/repository.rb +30 -84
- data/lib/geet/github/api_interface.rb +11 -3
- data/lib/geet/github/gist.rb +1 -0
- data/lib/geet/gitlab/api_interface.rb +5 -2
- data/lib/geet/helpers/os_helper.rb +36 -3
- data/lib/geet/helpers/summary_helper.rb +20 -0
- data/lib/geet/resources/{edit_summary_template.md → templates/edit_summary.md} +0 -3
- data/lib/geet/services/create_gist.rb +18 -2
- data/lib/geet/services/create_issue.rb +46 -21
- data/lib/geet/services/create_label.rb +8 -4
- data/lib/geet/services/create_pr.rb +67 -18
- data/lib/geet/services/list_issues.rb +9 -5
- data/lib/geet/services/list_labels.rb +6 -2
- data/lib/geet/services/list_milestones.rb +11 -7
- data/lib/geet/services/list_prs.rb +6 -2
- data/lib/geet/services/merge_pr.rb +18 -11
- data/lib/geet/utils/git_client.rb +160 -0
- data/lib/geet/utils/manual_list_selection.rb +41 -23
- data/lib/geet/version.rb +1 -1
- data/spec/integration/create_gist_spec.rb +2 -5
- data/spec/integration/create_issue_spec.rb +10 -10
- data/spec/integration/create_label_spec.rb +30 -5
- data/spec/integration/create_pr_spec.rb +85 -10
- data/spec/integration/list_issues_spec.rb +12 -11
- data/spec/integration/list_labels_spec.rb +28 -5
- data/spec/integration/list_milestones_spec.rb +30 -3
- data/spec/integration/list_prs_spec.rb +8 -7
- data/spec/integration/merge_pr_spec.rb +8 -7
- data/spec/vcr_cassettes/create_gist_private.yml +1 -1
- data/spec/vcr_cassettes/create_gist_public.yml +1 -1
- data/spec/vcr_cassettes/create_issue.yml +9 -9
- data/spec/vcr_cassettes/create_issue_upstream.yml +3 -3
- data/spec/vcr_cassettes/create_label.yml +1 -1
- data/spec/vcr_cassettes/create_label_upstream.yml +80 -0
- data/spec/vcr_cassettes/create_label_with_random_color.yml +1 -1
- data/spec/vcr_cassettes/create_pr.yml +13 -13
- data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +235 -0
- data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +235 -0
- data/spec/vcr_cassettes/create_pr_upstream.yml +4 -4
- data/spec/vcr_cassettes/github_com/list_issues.yml +5 -5
- data/spec/vcr_cassettes/github_com/list_issues_upstream.yml +6 -6
- data/spec/vcr_cassettes/github_com/list_issues_with_assignee.yml +4 -4
- data/spec/vcr_cassettes/github_com/list_labels.yml +1 -1
- data/spec/vcr_cassettes/github_com/list_labels_upstream.yml +78 -0
- data/spec/vcr_cassettes/gitlab_com/list_issues.yml +5 -5
- data/spec/vcr_cassettes/gitlab_com/list_labels.yml +1 -1
- data/spec/vcr_cassettes/list_milestones.yml +15 -15
- data/spec/vcr_cassettes/list_milestones_upstream.yml +155 -0
- data/spec/vcr_cassettes/list_prs.yml +6 -6
- data/spec/vcr_cassettes/list_prs_upstream.yml +3 -3
- data/spec/vcr_cassettes/merge_pr.yml +2 -2
- data/spec/vcr_cassettes/merge_pr_with_branch_deletion.yml +2 -2
- metadata +24 -4
- data/lib/geet/utils/git.rb +0 -30
@@ -3,12 +3,16 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListIssues
|
6
|
-
def
|
7
|
-
|
6
|
+
def initialize(repository)
|
7
|
+
@repository = repository
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(assignee_pattern: nil, output: $stdout, **)
|
11
|
+
assignee_thread = find_assignee(assignee_pattern, output) if assignee_pattern
|
8
12
|
|
9
13
|
assignee = assignee_thread&.join&.value
|
10
14
|
|
11
|
-
issues = repository.issues(assignee: assignee)
|
15
|
+
issues = @repository.issues(assignee: assignee)
|
12
16
|
|
13
17
|
issues.each do |issue|
|
14
18
|
output.puts "#{issue.number}. #{issue.title} (#{issue.link})"
|
@@ -17,11 +21,11 @@ module Geet
|
|
17
21
|
|
18
22
|
private
|
19
23
|
|
20
|
-
def find_assignee(
|
24
|
+
def find_assignee(assignee_pattern, output)
|
21
25
|
output.puts 'Finding assignee...'
|
22
26
|
|
23
27
|
Thread.new do
|
24
|
-
collaborators = repository.collaborators
|
28
|
+
collaborators = @repository.collaborators
|
25
29
|
collaborator = collaborators.find { |collaborator| collaborator =~ /#{assignee_pattern}/i }
|
26
30
|
collaborator || raise("No collaborator found for pattern: #{assignee_pattern.inspect}")
|
27
31
|
end
|
@@ -3,8 +3,12 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListLabels
|
6
|
-
def
|
7
|
-
|
6
|
+
def initialize(repository)
|
7
|
+
@repository = repository
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(output: $stdout)
|
11
|
+
labels = @repository.labels
|
8
12
|
|
9
13
|
labels.each do |label|
|
10
14
|
output.puts "- #{label.name} (##{label.color})"
|
@@ -3,9 +3,13 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListMilestones
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(repository)
|
7
|
+
@repository = repository
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(output: $stdout)
|
11
|
+
milestones = find_milestones(output)
|
12
|
+
issues_by_milestone_number = find_milestone_issues(milestones, output)
|
9
13
|
|
10
14
|
output.puts
|
11
15
|
|
@@ -30,13 +34,13 @@ module Geet
|
|
30
34
|
description
|
31
35
|
end
|
32
36
|
|
33
|
-
def find_milestones(
|
37
|
+
def find_milestones(output)
|
34
38
|
output.puts 'Finding milestones...'
|
35
39
|
|
36
|
-
repository.milestones
|
40
|
+
@repository.milestones
|
37
41
|
end
|
38
42
|
|
39
|
-
def find_milestone_issues(
|
43
|
+
def find_milestone_issues(milestones, output)
|
40
44
|
output.puts 'Finding issues...'
|
41
45
|
|
42
46
|
# Interestingly, on MRI, concurrent hash access is not a problem without mutex,
|
@@ -46,7 +50,7 @@ module Geet
|
|
46
50
|
|
47
51
|
issue_threads = milestones.map do |milestone|
|
48
52
|
Thread.new do
|
49
|
-
issues = repository.abstract_issues(milestone: milestone.number)
|
53
|
+
issues = @repository.abstract_issues(milestone: milestone.number)
|
50
54
|
|
51
55
|
mutex.synchronize do
|
52
56
|
issues_by_milestone_number[milestone.number] = issues
|
@@ -3,8 +3,12 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListPrs
|
6
|
-
def
|
7
|
-
|
6
|
+
def initialize(repository)
|
7
|
+
@repository = repository
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(output: $stdout)
|
11
|
+
prs = @repository.prs
|
8
12
|
|
9
13
|
prs.each do |pr|
|
10
14
|
output.puts "#{pr.number}. #{pr.title} (#{pr.link})"
|
@@ -3,25 +3,32 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class MergePr
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
|
7
|
+
|
8
|
+
def initialize(repository, git_client: DEFAULT_GIT_CLIENT)
|
9
|
+
@repository = repository
|
10
|
+
@git_client = git_client
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(delete_branch: false, output: $stdout)
|
14
|
+
merge_head = find_merge_head
|
15
|
+
pr = checked_find_branch_pr(merge_head, output)
|
9
16
|
merge_pr(pr, output)
|
10
|
-
do_delete_branch(
|
17
|
+
do_delete_branch(output) if delete_branch
|
11
18
|
pr
|
12
19
|
end
|
13
20
|
|
14
21
|
private
|
15
22
|
|
16
|
-
def find_merge_head
|
17
|
-
|
23
|
+
def find_merge_head
|
24
|
+
@git_client.current_branch
|
18
25
|
end
|
19
26
|
|
20
27
|
# Expect to find only one.
|
21
|
-
def checked_find_branch_pr(
|
28
|
+
def checked_find_branch_pr(head, output)
|
22
29
|
output.puts "Finding PR with head (#{head})..."
|
23
30
|
|
24
|
-
prs = repository.prs(head: head)
|
31
|
+
prs = @repository.prs(head: head)
|
25
32
|
|
26
33
|
raise "Expected to find only one PR for the current branch; found: #{prs.size}" if prs.size != 1
|
27
34
|
|
@@ -34,10 +41,10 @@ module Geet
|
|
34
41
|
pr.merge
|
35
42
|
end
|
36
43
|
|
37
|
-
def do_delete_branch(
|
38
|
-
output.puts "Deleting branch #{
|
44
|
+
def do_delete_branch(output)
|
45
|
+
output.puts "Deleting branch #{@git_client.current_branch}..."
|
39
46
|
|
40
|
-
repository.delete_branch(
|
47
|
+
@repository.delete_branch(@git_client.current_branch)
|
41
48
|
end
|
42
49
|
end
|
43
50
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'shellwords'
|
4
|
+
require_relative '../helpers/os_helper.rb'
|
5
|
+
|
6
|
+
module Geet
|
7
|
+
module Utils
|
8
|
+
# Represents the git program interface; used for performing git operations.
|
9
|
+
#
|
10
|
+
class GitClient
|
11
|
+
include Geet::Helpers::OsHelper
|
12
|
+
|
13
|
+
ORIGIN_NAME = 'origin'
|
14
|
+
UPSTREAM_NAME = 'upstream'
|
15
|
+
|
16
|
+
# For simplicity, we match any character except the ones the separators.
|
17
|
+
REMOTE_ORIGIN_REGEX = %r{
|
18
|
+
\A
|
19
|
+
(?:https://(.+?)/|git@(.+?):)
|
20
|
+
([^/]+/.*?)
|
21
|
+
(?:\.git)?
|
22
|
+
\Z
|
23
|
+
}x
|
24
|
+
|
25
|
+
UPSTREAM_BRANCH_REGEX = %r{\A[^/]+/([^/]+)\Z}
|
26
|
+
|
27
|
+
CLEAN_TREE_MESSAGE_REGEX = /^nothing to commit, working tree clean$/
|
28
|
+
|
29
|
+
def initialize(location: nil)
|
30
|
+
@location = location
|
31
|
+
end
|
32
|
+
|
33
|
+
##########################################################################
|
34
|
+
# BRANCH/TREE APIS
|
35
|
+
##########################################################################
|
36
|
+
|
37
|
+
# Return the commit shas between HEAD and `limit`, excluding the already applied commits
|
38
|
+
# (which start with `-`)
|
39
|
+
#
|
40
|
+
def cherry(limit)
|
41
|
+
raw_commits = execute_command("git #{gitdir_option} cherry #{limit.shellescape}")
|
42
|
+
|
43
|
+
raw_commits.split("\n").grep(/^\+/).map { |line| line[3..-1] }
|
44
|
+
end
|
45
|
+
|
46
|
+
def current_branch
|
47
|
+
branch = execute_command("git #{gitdir_option} rev-parse --abbrev-ref HEAD")
|
48
|
+
|
49
|
+
raise "Couldn't find current branch" if branch == 'HEAD'
|
50
|
+
|
51
|
+
branch
|
52
|
+
end
|
53
|
+
|
54
|
+
# Not to be confused with `upstream` repository!
|
55
|
+
#
|
56
|
+
# return: nil, if the upstream branch is not configured.
|
57
|
+
#
|
58
|
+
def upstream_branch
|
59
|
+
head_symbolic_ref = execute_command("git #{gitdir_option} symbolic-ref -q HEAD")
|
60
|
+
|
61
|
+
raw_upstream_branch = execute_command("git #{gitdir_option} for-each-ref --format='%(upstream:short)' #{head_symbolic_ref.shellescape}").strip
|
62
|
+
|
63
|
+
if raw_upstream_branch != ''
|
64
|
+
raw_upstream_branch[UPSTREAM_BRANCH_REGEX, 1] || raise("Unexpected upstream format: #{raw_upstream_branch}")
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def working_tree_clean?
|
71
|
+
git_message = execute_command("git #{gitdir_option} status")
|
72
|
+
|
73
|
+
!!(git_message =~ CLEAN_TREE_MESSAGE_REGEX)
|
74
|
+
end
|
75
|
+
|
76
|
+
##########################################################################
|
77
|
+
# COMMIT/OBJECT APIS
|
78
|
+
##########################################################################
|
79
|
+
|
80
|
+
# Show the description ("<subject>\n\n<body>") for the given git object.
|
81
|
+
#
|
82
|
+
def show_description(object)
|
83
|
+
execute_command("git #{gitdir_option} show --quiet --format='%s\n\n%b' #{object.shellescape}")
|
84
|
+
end
|
85
|
+
|
86
|
+
##########################################################################
|
87
|
+
# REPOSITORY/REMOTE APIS
|
88
|
+
##########################################################################
|
89
|
+
|
90
|
+
# Example: `donaldduck/geet`
|
91
|
+
#
|
92
|
+
def path(upstream: false)
|
93
|
+
remote_name = upstream ? UPSTREAM_NAME : ORIGIN_NAME
|
94
|
+
|
95
|
+
remote(remote_name)[REMOTE_ORIGIN_REGEX, 3]
|
96
|
+
end
|
97
|
+
|
98
|
+
def provider_domain
|
99
|
+
# We assume that it's not possible to have origin and upstream on different providers.
|
100
|
+
#
|
101
|
+
remote_url = remote(ORIGIN_NAME)
|
102
|
+
|
103
|
+
domain = remote_url[REMOTE_ORIGIN_REGEX, 1] || remote_url[REMOTE_ORIGIN_REGEX, 2]
|
104
|
+
|
105
|
+
raise "Can't identify domain in the provider domain string: #{domain}" if domain !~ /(.*)\.\w+/
|
106
|
+
|
107
|
+
domain
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns the URL of the remote with the given name.
|
111
|
+
# Sanity checks are performed.
|
112
|
+
#
|
113
|
+
# The result is in the format `git@github.com:donaldduck/geet.git`
|
114
|
+
#
|
115
|
+
def remote(name)
|
116
|
+
remote_url = execute_command("git #{gitdir_option} ls-remote --get-url #{name}")
|
117
|
+
|
118
|
+
if remote_url == name
|
119
|
+
raise "Remote #{name.inspect} not found!"
|
120
|
+
elsif remote_url !~ REMOTE_ORIGIN_REGEX
|
121
|
+
raise "Unexpected remote reference format: #{remote_url.inspect}"
|
122
|
+
end
|
123
|
+
|
124
|
+
remote_url
|
125
|
+
end
|
126
|
+
|
127
|
+
# Doesn't sanity check for the remote url format; this action is for querying
|
128
|
+
# purposes, any any action that needs to work with the remote, uses #remote.
|
129
|
+
#
|
130
|
+
def remote_defined?(name)
|
131
|
+
remote_url = execute_command("git #{gitdir_option} ls-remote --get-url #{name}")
|
132
|
+
|
133
|
+
# If the remote is not define, `git ls-remote` will return the passed value.
|
134
|
+
remote_url != name
|
135
|
+
end
|
136
|
+
|
137
|
+
##########################################################################
|
138
|
+
# OPERATION APIS
|
139
|
+
##########################################################################
|
140
|
+
|
141
|
+
# upstream_branch: create an upstream branch.
|
142
|
+
#
|
143
|
+
def push(upstream_branch: nil)
|
144
|
+
upstream_branch_option = "-u origin #{upstream_branch.shellescape}" if upstream_branch
|
145
|
+
|
146
|
+
execute_command("git #{gitdir_option} push #{upstream_branch_option}")
|
147
|
+
end
|
148
|
+
|
149
|
+
##########################################################################
|
150
|
+
# INTERNAL HELPERS
|
151
|
+
##########################################################################
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def gitdir_option
|
156
|
+
"--git-dir #{@location.shellescape}/.git" if @location
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -5,41 +5,59 @@ require 'temp-fork-tp-filter'
|
|
5
5
|
module Geet
|
6
6
|
module Utils
|
7
7
|
class ManualListSelection
|
8
|
-
|
8
|
+
NO_SELECTION_KEY = '(none)'
|
9
9
|
|
10
|
-
|
11
|
-
single: :select,
|
12
|
-
multiple: :multi_select,
|
13
|
-
}
|
10
|
+
PAGER_SIZE = 16
|
14
11
|
|
15
|
-
#
|
12
|
+
# entry_type: description of the entries type.
|
13
|
+
# entries: array of objects; if they're not strings, must also pass :instance_method.
|
14
|
+
# this value must not be empty.
|
15
|
+
# selection_type: :single or :multiple
|
16
|
+
# instance_method: required when non-string objects are passed as entries; its invocation on
|
17
|
+
# each object must return a string, which is used as key.
|
18
|
+
#
|
19
|
+
# returns: the selected entry or array of entries. for single selection, if no entries are
|
20
|
+
# chosen, nil is returned.
|
21
|
+
#
|
16
22
|
def select(entry_type, entries, selection_type, instance_method: nil)
|
17
|
-
|
23
|
+
check_entries(entries)
|
18
24
|
|
19
|
-
|
20
|
-
|
25
|
+
entries = create_entries_map(entries, instance_method)
|
26
|
+
|
27
|
+
result = show_prompt(entry_type, selection_type, entries)
|
28
|
+
|
29
|
+
result
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
21
33
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
34
|
+
def check_entries(entries)
|
35
|
+
raise "No #{entry_type} provided!" if entries.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_entries_map(entries, instance_method)
|
39
|
+
entries.each_with_object({}) do |entry, current_map|
|
40
|
+
key = instance_method ? entry.send(instance_method) : entry
|
41
|
+
current_map[key] = entry
|
26
42
|
end
|
43
|
+
end
|
27
44
|
|
28
|
-
|
45
|
+
def show_prompt(entry_type, selection_type, entries)
|
46
|
+
prompt_title = "Please select the #{entry_type}(s):"
|
29
47
|
|
30
|
-
|
31
|
-
|
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)
|
32
54
|
else
|
33
|
-
raise "
|
55
|
+
raise "Unexpected selection type: #{selection_type.inspect}"
|
34
56
|
end
|
35
|
-
|
36
|
-
selected_entries
|
37
57
|
end
|
38
58
|
|
39
|
-
|
40
|
-
|
41
|
-
def find_prompt_method(selection_type)
|
42
|
-
PROMPT_METHODS[selection_type] || raise("Unrecognized selection_type: #{selection_type}")
|
59
|
+
def add_no_selection_entry(entries)
|
60
|
+
{NO_SELECTION_KEY => nil}.merge(entries)
|
43
61
|
end
|
44
62
|
end
|
45
63
|
end
|
data/lib/geet/version.rb
CHANGED
@@ -7,7 +7,6 @@ require_relative '../../lib/geet/git/repository'
|
|
7
7
|
require_relative '../../lib/geet/services/create_gist'
|
8
8
|
|
9
9
|
describe Geet::Services::CreateGist do
|
10
|
-
let(:repository) { Geet::Git::Repository.new }
|
11
10
|
let(:tempfile) { Tempfile.open('geet_gist') { |file| file << 'testcontent' } }
|
12
11
|
|
13
12
|
it 'should create a public gist' do
|
@@ -20,8 +19,7 @@ describe Geet::Services::CreateGist do
|
|
20
19
|
|
21
20
|
VCR.use_cassette('create_gist_public') do
|
22
21
|
described_class.new.execute(
|
23
|
-
|
24
|
-
description: 'testdescription', publik: true, no_browse: true, output: actual_output
|
22
|
+
tempfile.path, description: 'testdescription', publik: true, no_browse: true, output: actual_output
|
25
23
|
)
|
26
24
|
end
|
27
25
|
|
@@ -38,8 +36,7 @@ describe Geet::Services::CreateGist do
|
|
38
36
|
|
39
37
|
VCR.use_cassette('create_gist_private') do
|
40
38
|
described_class.new.execute(
|
41
|
-
|
42
|
-
description: 'testdescription', no_browse: true, output: actual_output
|
39
|
+
tempfile.path, description: 'testdescription', no_browse: true, output: actual_output
|
43
40
|
)
|
44
41
|
end
|
45
42
|
|
@@ -6,12 +6,13 @@ require_relative '../../lib/geet/git/repository'
|
|
6
6
|
require_relative '../../lib/geet/services/create_issue'
|
7
7
|
|
8
8
|
describe Geet::Services::CreateIssue do
|
9
|
-
let(:
|
10
|
-
let(:
|
9
|
+
let(:git_client) { Geet::Utils::GitClient.new }
|
10
|
+
let(:repository) { Geet::Git::Repository.new(git_client: git_client) }
|
11
|
+
let(:upstream_repository) { Geet::Git::Repository.new(upstream: true, git_client: git_client) }
|
11
12
|
|
12
13
|
context 'with labels, assignees and milestones' do
|
13
14
|
it 'should create an issue' do
|
14
|
-
allow(
|
15
|
+
allow(git_client).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo')
|
15
16
|
|
16
17
|
expected_output = <<~STR
|
17
18
|
Finding labels...
|
@@ -27,8 +28,8 @@ describe Geet::Services::CreateIssue do
|
|
27
28
|
actual_output = StringIO.new
|
28
29
|
|
29
30
|
actual_created_issue = VCR.use_cassette('create_issue') do
|
30
|
-
described_class.new.execute(
|
31
|
-
|
31
|
+
described_class.new(repository).execute(
|
32
|
+
'Title', 'Description',
|
32
33
|
label_patterns: 'bug,invalid', milestone_pattern: '0.0.1', assignee_patterns: 'nald-ts,nald-fr',
|
33
34
|
no_open_issue: true, output: actual_output
|
34
35
|
)
|
@@ -43,13 +44,12 @@ describe Geet::Services::CreateIssue do
|
|
43
44
|
end
|
44
45
|
|
45
46
|
it 'should create an upstream issue' do
|
46
|
-
allow(
|
47
|
-
allow(
|
48
|
-
allow(
|
47
|
+
allow(git_client).to receive(:current_branch).and_return('mybranch')
|
48
|
+
allow(git_client).to receive(:remote).with('origin').and_return('git@github.com:donaldduck/testrepo')
|
49
|
+
allow(git_client).to receive(:remote).with('upstream').and_return('git@github.com:donald-fr/testrepo_u')
|
49
50
|
|
50
51
|
expected_output = <<~STR
|
51
52
|
Creating the issue...
|
52
|
-
Assigning authenticated user...
|
53
53
|
Issue address: https://github.com/donald-fr/testrepo_u/issues/7
|
54
54
|
STR
|
55
55
|
|
@@ -57,7 +57,7 @@ describe Geet::Services::CreateIssue do
|
|
57
57
|
|
58
58
|
actual_created_issue = VCR.use_cassette('create_issue_upstream') do
|
59
59
|
create_options = { no_open_issue: true, output: actual_output }
|
60
|
-
described_class.new.execute(
|
60
|
+
described_class.new(upstream_repository).execute('Title', 'Description', create_options)
|
61
61
|
end
|
62
62
|
|
63
63
|
expect(actual_output.string).to eql(expected_output)
|