geet 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -10
  3. data/Gemfile.lock +8 -2
  4. data/README.md +27 -2
  5. data/Rakefile +3 -1
  6. data/bin/geet +37 -17
  7. data/geet.gemspec +3 -1
  8. data/lib/geet/commandline/configuration.rb +18 -5
  9. data/lib/geet/commandline/editor.rb +14 -24
  10. data/lib/geet/git/repository.rb +30 -84
  11. data/lib/geet/github/api_interface.rb +11 -3
  12. data/lib/geet/github/gist.rb +1 -0
  13. data/lib/geet/gitlab/api_interface.rb +5 -2
  14. data/lib/geet/helpers/os_helper.rb +36 -3
  15. data/lib/geet/helpers/summary_helper.rb +20 -0
  16. data/lib/geet/resources/{edit_summary_template.md → templates/edit_summary.md} +0 -3
  17. data/lib/geet/services/create_gist.rb +18 -2
  18. data/lib/geet/services/create_issue.rb +46 -21
  19. data/lib/geet/services/create_label.rb +8 -4
  20. data/lib/geet/services/create_pr.rb +67 -18
  21. data/lib/geet/services/list_issues.rb +9 -5
  22. data/lib/geet/services/list_labels.rb +6 -2
  23. data/lib/geet/services/list_milestones.rb +11 -7
  24. data/lib/geet/services/list_prs.rb +6 -2
  25. data/lib/geet/services/merge_pr.rb +18 -11
  26. data/lib/geet/utils/git_client.rb +160 -0
  27. data/lib/geet/utils/manual_list_selection.rb +41 -23
  28. data/lib/geet/version.rb +1 -1
  29. data/spec/integration/create_gist_spec.rb +2 -5
  30. data/spec/integration/create_issue_spec.rb +10 -10
  31. data/spec/integration/create_label_spec.rb +30 -5
  32. data/spec/integration/create_pr_spec.rb +85 -10
  33. data/spec/integration/list_issues_spec.rb +12 -11
  34. data/spec/integration/list_labels_spec.rb +28 -5
  35. data/spec/integration/list_milestones_spec.rb +30 -3
  36. data/spec/integration/list_prs_spec.rb +8 -7
  37. data/spec/integration/merge_pr_spec.rb +8 -7
  38. data/spec/vcr_cassettes/create_gist_private.yml +1 -1
  39. data/spec/vcr_cassettes/create_gist_public.yml +1 -1
  40. data/spec/vcr_cassettes/create_issue.yml +9 -9
  41. data/spec/vcr_cassettes/create_issue_upstream.yml +3 -3
  42. data/spec/vcr_cassettes/create_label.yml +1 -1
  43. data/spec/vcr_cassettes/create_label_upstream.yml +80 -0
  44. data/spec/vcr_cassettes/create_label_with_random_color.yml +1 -1
  45. data/spec/vcr_cassettes/create_pr.yml +13 -13
  46. data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +235 -0
  47. data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +235 -0
  48. data/spec/vcr_cassettes/create_pr_upstream.yml +4 -4
  49. data/spec/vcr_cassettes/github_com/list_issues.yml +5 -5
  50. data/spec/vcr_cassettes/github_com/list_issues_upstream.yml +6 -6
  51. data/spec/vcr_cassettes/github_com/list_issues_with_assignee.yml +4 -4
  52. data/spec/vcr_cassettes/github_com/list_labels.yml +1 -1
  53. data/spec/vcr_cassettes/github_com/list_labels_upstream.yml +78 -0
  54. data/spec/vcr_cassettes/gitlab_com/list_issues.yml +5 -5
  55. data/spec/vcr_cassettes/gitlab_com/list_labels.yml +1 -1
  56. data/spec/vcr_cassettes/list_milestones.yml +15 -15
  57. data/spec/vcr_cassettes/list_milestones_upstream.yml +155 -0
  58. data/spec/vcr_cassettes/list_prs.yml +6 -6
  59. data/spec/vcr_cassettes/list_prs_upstream.yml +3 -3
  60. data/spec/vcr_cassettes/merge_pr.yml +2 -2
  61. data/spec/vcr_cassettes/merge_pr_with_branch_deletion.yml +2 -2
  62. metadata +24 -4
  63. data/lib/geet/utils/git.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37b511c318e9f2cb1c18ecf1a1f247236c841040
4
- data.tar.gz: 61aeabbdbd6e3616e49247acf47ffbbbf18d8085
3
+ metadata.gz: a73b4ce8509349204e7abc8c667856acf8baa421
4
+ data.tar.gz: b94ef51efb18f859f7aa547cb718861a2ca03eeb
5
5
  SHA512:
6
- metadata.gz: 6692e7597431f0d0ef9d194030086112985f7f1f2e4e0b6b8caf3c6dbeea565fd3d22b7b0033cf3290bf156e6f331e4e70ea6b3cf3be962e45110aa32ffdf05c
7
- data.tar.gz: e57f240a2c9a3b0ecb65a874efa7f3c4c61e0102cd365c7a53ac6b2579367c37c95dae072014f33ac5d6077ca75df649aff0dd4e7912a92502503e5a6a0e554e
6
+ metadata.gz: f07424e685a1265e5e083889c9ee627893f63bbcb56d268b2fe5cfabd2e475f98bade4c9eca5e67da4a84e53e6652c3dbecb05fd5f4b3acbc8fe05819b9250d5
7
+ data.tar.gz: acabfcbaa84a7e3f0423706ca3a84a95ce779f8bf6771a6b1b02a7920a54b3068922ec241c61ad275af12fd7b08469ffd78fb91e575ecc0d8e335278a4aac968
data/Gemfile CHANGED
@@ -2,19 +2,15 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
-
7
- gem 'simple_scripting', '~> 0.9.3'
8
- gem 'temp-fork-tp-filter', '= 0.0.3'
9
-
10
- group :development, :test do
11
- gem 'byebug', '~> 9.1.0'
12
- gem 'rake', '~> 12.3.0'
13
- gem 'rubocop', '~> 0.52.0'
14
- end
5
+ gemspec
15
6
 
16
7
  group :test do
17
8
  gem 'rspec', '~> 3.7.0'
18
9
  gem 'vcr', '~> 3.0.3'
19
10
  gem 'webmock', '~> 3.1.1'
20
11
  end
12
+
13
+ group :tools do
14
+ gem 'byebug', '~> 9.1.0'
15
+ gem 'rubocop', '~> 0.52.0'
16
+ end
data/Gemfile.lock CHANGED
@@ -1,3 +1,10 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ geet (0.3.0)
5
+ simple_scripting (~> 0.9.3)
6
+ temp-fork-tp-filter (= 0.0.3)
7
+
1
8
  GEM
2
9
  remote: https://rubygems.org/
3
10
  specs:
@@ -75,11 +82,10 @@ PLATFORMS
75
82
 
76
83
  DEPENDENCIES
77
84
  byebug (~> 9.1.0)
85
+ geet!
78
86
  rake (~> 12.3.0)
79
87
  rspec (~> 3.7.0)
80
88
  rubocop (~> 0.52.0)
81
- simple_scripting (~> 0.9.3)
82
- temp-fork-tp-filter (= 0.0.3)
83
89
  vcr (~> 3.0.3)
84
90
  webmock (~> 3.1.1)
85
91
 
data/README.md CHANGED
@@ -55,6 +55,31 @@ patterns are partial matches, so, for example, `johncarmack` will be matched as
55
55
 
56
56
  After creation, the issue page will be automatically opened in the default browser.
57
57
 
58
+ ### Using menus for options selection
59
+
60
+ Geet supports selecting options (labels, collaborators, etc.), using the `-` parameter:
61
+
62
+ $ geet issue create --label-patterns -
63
+
64
+ This will show a menu like the following:
65
+
66
+ Please select the label(s): (Use arrow keys, press Space to select and Enter to finish, and alphanumeric/underscore characters to filter)
67
+ ‣ ⬡ bug
68
+ ⬡ enhancement
69
+ ⬡ not_an_issue
70
+ ⬡ requires_design
71
+ ⬡ technical_debt
72
+ ⬡ top_priority
73
+ ⬡ ux
74
+
75
+ Typing alphanumeric keys and underscore will enable filtering:
76
+
77
+ Please select the label(s): (Filter: "b")
78
+ ‣ ⬡ bug
79
+ ⬡ technical_debt
80
+
81
+ When a filter is active, use `Backspace` to cancel the last character, and `Canc` to reset it.
82
+
58
83
  ### Create a PR (with label, reviewers, and assigned to self)
59
84
 
60
85
  Basic creation of a PR:
@@ -132,8 +157,8 @@ Examples:
132
157
 
133
158
  ## Development status
134
159
 
135
- Geet is in alpha status. Although I use it daily, new features are frequently added, and internal/external APIs/workflows may change.
160
+ Geet is in beta status. Although I use it daily, new features are frequently added, and internal/external APIs/workflows may change.
136
161
 
137
- The public release will be 1.0, and is expected to be released in February 2018 or earlier.
162
+ The public release will be 1.0.
138
163
 
139
164
  [BS img]: https://travis-ci.org/saveriomiroddi/geet.svg?branch=master
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rspec/core/rake_task'
2
2
 
3
- RSpec::Core::RakeTask.new(:spec)
3
+ RSpec::Core::RakeTask.new(:spec) do |task|
4
+ task.rspec_opts = ['--order rand']
5
+ end
4
6
 
5
7
  task default: :spec
data/bin/geet CHANGED
@@ -5,17 +5,20 @@ require_relative '../lib/geet/commandline/configuration.rb'
5
5
  require_relative '../lib/geet/commandline/commands.rb'
6
6
  require_relative '../lib/geet/commandline/editor.rb'
7
7
  require_relative '../lib/geet/git/repository.rb'
8
- require_relative '../lib/geet/utils/git.rb'
8
+ require_relative '../lib/geet/helpers/summary_helper.rb'
9
+ require_relative '../lib/geet/utils/git_client.rb'
9
10
  Dir[File.join(__dir__, '../lib/geet/services/*.rb')].each { |filename| require filename }
10
11
 
11
12
  class GeetLauncher
12
13
  include Geet
13
14
  include Geet::Commandline::Commands
15
+ include Geet::Helpers::SummaryHelper
16
+
17
+ SUMMARY_TEMPLATE = IO.read(File.expand_path('../lib/geet/resources/templates/edit_summary.md', __dir__))
14
18
 
15
19
  def launch
16
20
  command, options = Commandline::Configuration.new.decode_argv || exit
17
21
 
18
- # `:upstream` is always false in the gist command case.
19
22
  repository = Git::Repository.new(upstream: !!options[:upstream])
20
23
 
21
24
  case command
@@ -23,40 +26,57 @@ class GeetLauncher
23
26
  filename = options.delete(:filename)
24
27
  options[:publik] = options.delete(:public) if options.key?(:public)
25
28
 
26
- Services::CreateGist.new.execute(repository, filename, options)
29
+ Services::CreateGist.new.execute(filename, options)
27
30
  when ISSUE_CREATE_COMMAND
28
- title, description = Commandline::Editor.new.edit_summary
31
+ summary = options[:summary] || Commandline::Editor.new.edit_content(help: SUMMARY_TEMPLATE)
32
+ title, description = split_summary(summary)
33
+
29
34
  options[:milestone_pattern] = options.delete(:milestone) if options.key?(:milestone)
30
35
 
31
- Services::CreateIssue.new.execute(repository, title, description, options)
36
+ Services::CreateIssue.new(repository).execute(title, description, options)
32
37
  when LABEL_CREATE_COMMAND
33
38
  name = options.delete(:name)
34
39
 
35
- Services::CreateLabel.new.execute(repository, name, options)
40
+ Services::CreateLabel.new(repository).execute(name, options)
36
41
  when ISSUE_LIST_COMMAND
37
- Services::ListIssues.new.execute(repository, options)
42
+ Services::ListIssues.new(repository).execute(options)
38
43
  when LABEL_LIST_COMMAND
39
- Services::ListLabels.new.execute(repository)
44
+ Services::ListLabels.new(repository).execute
40
45
  when MILESTONE_LIST_COMMAND
41
- Services::ListMilestones.new.execute(repository)
46
+ Services::ListMilestones.new(repository).execute
42
47
  when PR_CREATE_COMMAND
43
- # Tricky. It would be best to have Git logic exlusively inside the services,
44
- # but at the same time, the summary editing should be out.
45
- git = Utils::Git.new(repository)
46
- summary = git.cherry('master').size == 1 ? git.show_description('HEAD') : ''
48
+ summary = options[:summary] || edit_pr_summary
49
+ title, description = split_summary(summary)
47
50
 
48
- title, description = Commandline::Editor.new.edit_summary(summary: summary)
49
51
  options[:milestone_pattern] = options.delete(:milestone) if options.key?(:milestone)
50
52
 
51
- Services::CreatePr.new.execute(repository, title, description, options)
53
+ Services::CreatePr.new(repository).execute(title, description, options)
52
54
  when PR_LIST_COMMAND
53
- Services::ListPrs.new.execute(repository)
55
+ Services::ListPrs.new(repository).execute
54
56
  when PR_MERGE_COMMAND
55
- Services::MergePr.new.execute(repository, options)
57
+ Services::MergePr.new(repository).execute(options)
56
58
  else
57
59
  raise "Internal error - Unrecognized command #{command.inspect}"
58
60
  end
59
61
  end
62
+
63
+ private
64
+
65
+ def edit_pr_summary
66
+ # Tricky. It would be best to have Git logic exlusively inside the services,
67
+ # but at the same time, the summary editing should be out.
68
+ git = Utils::GitClient.new
69
+ pr_commits = git.cherry('master')
70
+
71
+ if pr_commits.size == 1
72
+ prepopulated_summary = git.show_description('HEAD')
73
+ cancel_pr_help = "In order to cancel the PR creation, delete the description above.\n"
74
+
75
+ Commandline::Editor.new.edit_content(content: prepopulated_summary, help: SUMMARY_TEMPLATE + cancel_pr_help)
76
+ else
77
+ Commandline::Editor.new.edit_content(help: SUMMARY_TEMPLATE)
78
+ end
79
+ end
60
80
  end
61
81
 
62
82
  GeetLauncher.new.launch if $PROGRAM_NAME == __FILE__
data/geet.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.required_ruby_version = '>= 2.3.0'
12
12
  s.authors = ['Saverio Miroddi']
13
- s.date = '2018-01-19'
13
+ s.date = '2018-01-25'
14
14
  s.email = ['saverio.pub2@gmail.com']
15
15
  s.homepage = 'https://github.com/saveriomiroddi/geet'
16
16
  s.summary = 'Commandline interface for performing SCM (eg. GitHub) operations (eg. PR creation).'
@@ -20,6 +20,8 @@ Gem::Specification.new do |s|
20
20
  s.add_runtime_dependency 'simple_scripting', '~> 0.9.3'
21
21
  s.add_runtime_dependency 'temp-fork-tp-filter', '= 0.0.3'
22
22
 
23
+ s.add_development_dependency 'rake', '~> 12.3.0'
24
+
23
25
  s.files = `git ls-files`.split("\n")
24
26
  s.executables << 'geet'
25
27
  s.require_paths = ['lib']
@@ -24,13 +24,15 @@ module Geet
24
24
  ['-n', '--no-open-issue', "Don't open the issue link in the browser after creation"],
25
25
  ['-l', '--label-patterns "bug,help wanted"', 'Label patterns'],
26
26
  ['-m', '--milestone 1.5.0', 'Milestone title pattern'],
27
- ['-a', '--assignee-patterns john,tom,adrian,kevin', 'Assignee login patterns. Defaults to authenticated user'],
27
+ ['-a', '--assignee-patterns john,tom,adrian,kevin', 'Assignee login patterns'],
28
+ ['-s', '--summary title_and_description', 'Set the summary (title and optionally description'],
28
29
  ['-u', '--upstream', 'Create on the upstream repository'],
29
30
  long_help: 'The default editor will be opened for editing title and description.'
30
31
  ]
31
32
 
32
33
  LABEL_CREATE_OPTIONS = [
33
34
  ['-c', '--color color', '6-digits hex color; if not specified, a random one is created'],
35
+ ['-u', '--upstream', 'Create on the upstream repository'],
34
36
  'name',
35
37
  ].freeze
36
38
 
@@ -39,18 +41,29 @@ module Geet
39
41
  ['-u', '--upstream', 'List on the upstream repository'],
40
42
  ].freeze
41
43
 
42
- LABEL_LIST_OPTIONS = [].freeze
44
+ LABEL_LIST_OPTIONS = [
45
+ ['-u', '--upstream', 'List on the upstream repository'],
46
+ ].freeze
43
47
 
44
- MILESTONE_LIST_OPTIONS = [].freeze
48
+ MILESTONE_LIST_OPTIONS = [
49
+ ['-u', '--upstream', 'List on the upstream repository'],
50
+ ].freeze
45
51
 
46
52
  PR_CREATE_OPTIONS = [
53
+ ['-A', '--automated-mode', "Automate the branch operations (see long help)"],
47
54
  ['-n', '--no-open-pr', "Don't open the PR link in the browser after creation"],
48
55
  ['-l', '--label-patterns "legacy,code review"', 'Label patterns'],
49
56
  ['-m', '--milestone 1.5.0', 'Milestone title pattern'],
50
57
  ['-r', '--reviewer-patterns john,tom,adrian,kevin', 'Reviewer login patterns'],
58
+ ['-s', '--summary title_and_description', 'Set the summary (title and optionally description'],
51
59
  ['-u', '--upstream', 'Create on the upstream repository'],
52
- long_help: 'The default editor will be opened for editing title and description; if the PR adds one commit only, '\
53
- 'the content will be prepopulated with the commit description.'
60
+ long_help: <<~STR
61
+ The default editor will be opened for editing title and description; if the PR adds one commit only, the content will be prepopulated with the commit description.
62
+
63
+ The "automated mode" will automate branch operations:
64
+ - raise an error if the current tree is dirty;
65
+ - if the upstream branch is not present, it will create it, otherwise, it will perform a push.
66
+ STR
54
67
  ]
55
68
 
56
69
  PR_LIST_OPTIONS = [
@@ -7,23 +7,24 @@ require_relative '../helpers/os_helper.rb'
7
7
  module Geet
8
8
  module Commandline
9
9
  class Editor
10
- # Liberally ripp..., ahem, inspired from git.
11
- SUMMARY_TEMPLATE = File.expand_path('../resources/edit_summary_template.md', __dir__)
12
- SUMMARY_TEMPLATE_SEPARATOR = '------------------------ >8 ------------------------'
13
-
14
10
  include Geet::Helpers::OsHelper
15
11
 
16
- # Edits a summary in the default editor, providing the SUMMARY_TEMPLATE.
12
+ # Git style!
13
+ HELP_SEPARATOR = '------------------------ >8 ------------------------'
14
+
15
+ # Edits a content in the default editor, optionally providing help.
17
16
  #
18
- # A summary is a composition with a title and an optional description;
19
- # if the description is not found, a blank string is returned.
17
+ # When the help is provided, it's appended to the bottom, separated by HELP_SEPARATOR.
18
+ # The help is stripped after the content if edited.
20
19
  #
21
- def edit_summary(summary: '')
22
- full_summary = summary + IO.read(SUMMARY_TEMPLATE)
20
+ def edit_content(content: '', help: nil)
21
+ content += "\n\n" + HELP_SEPARATOR + "\n" + help if help
23
22
 
24
- raw_summary = edit_content_in_default_editor(full_summary)
23
+ edited_content = edit_content_in_default_editor(content)
25
24
 
26
- split_raw_summary(raw_summary)
25
+ edited_content = edited_content.split(HELP_SEPARATOR, 2).first if help
26
+
27
+ edited_content.strip
27
28
  end
28
29
 
29
30
  private
@@ -36,8 +37,9 @@ module Geet
36
37
  #
37
38
  def edit_content_in_default_editor(content)
38
39
  tempfile = Tempfile.open(['geet_editor', '.md']) { |file| file << content }.path
40
+ command = "#{system_editor} #{tempfile.shellescape}"
39
41
 
40
- execute_command('editing', system_editor, tempfile)
42
+ execute_command(command, description: 'editing', interactive: true)
41
43
 
42
44
  content = IO.read(tempfile)
43
45
 
@@ -46,18 +48,6 @@ module Geet
46
48
  content
47
49
  end
48
50
 
49
- def split_raw_summary(raw_summary)
50
- raw_summary, _ = raw_summary.strip.split(SUMMARY_TEMPLATE_SEPARATOR, 2)
51
-
52
- raise "Missing title!" if raw_summary.empty?
53
-
54
- title, description = raw_summary.split(/\r|\n/, 2)
55
-
56
- # The title may have a residual newline char; the description may not be present,
57
- # or have multiple blank lines.
58
- [title.strip, description.to_s.strip]
59
- end
60
-
61
51
  # HELPERS ##########################################################################
62
52
 
63
53
  def system_editor
@@ -1,28 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'shellwords'
4
+ require_relative '../utils/git_client'
4
5
 
5
6
  module Geet
6
7
  module Git
7
8
  # This class represents, for convenience, both the local and the remote repository, but the
8
9
  # remote code is separated in each provider module.
9
10
  class Repository
10
- # For simplicity, we match any character except the ones the separators.
11
- REMOTE_ORIGIN_REGEX = %r{
12
- \A
13
- (?:https://(.+?)/|git@(.+?):)
14
- ([^/]+/.*?)
15
- (?:\.git)?
16
- \Z
17
- }x
18
-
19
- ORIGIN_NAME = 'origin'
20
- UPSTREAM_NAME = 'upstream'
21
-
22
- def initialize(upstream: false, location: nil)
11
+ CONFIRM_ACTION_TEXT = <<~STR
12
+ WARNING! The action will be performed on a fork, but an upstream repository has been found!
13
+ Press Enter to continue, or Ctrl+C to exit now.
14
+ STR
15
+
16
+ DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
17
+
18
+ def initialize(upstream: false, git_client: DEFAULT_GIT_CLIENT, warnings: true)
23
19
  @upstream = upstream
24
- @location = location
20
+ @git_client = git_client
25
21
  @api_token = extract_env_api_token
22
+ @warnings = warnings
26
23
  end
27
24
 
28
25
  # REMOTE FUNCTIONALITIES (REPOSITORY)
@@ -35,12 +32,8 @@ module Geet
35
32
  attempt_provider_call(:Label, :list, api_interface)
36
33
  end
37
34
 
38
- def create_gist(filename, content, description: nil, publik: false)
39
- attempt_provider_call(:Gist, :create, filename, content, api_interface, description: description, publik: publik)
40
- end
41
-
42
35
  def create_issue(title, description)
43
- ask_confirm_action if location_action_with_upstream_repository?
36
+ ask_confirm_action if local_action_with_upstream_repository? && @warnings
44
37
  attempt_provider_call(:Issue, :create, title, description, api_interface)
45
38
  end
46
39
 
@@ -69,7 +62,7 @@ module Geet
69
62
  end
70
63
 
71
64
  def create_pr(title, description, head)
72
- ask_confirm_action if location_action_with_upstream_repository?
65
+ ask_confirm_action if local_action_with_upstream_repository? && @warnings
73
66
  attempt_provider_call(:PR, :create, title, description, head, api_interface)
74
67
  end
75
68
 
@@ -85,69 +78,25 @@ module Geet
85
78
 
86
79
  # OTHER/CONVENIENCE FUNCTIONALITIES
87
80
 
88
- def current_branch
89
- gitdir_option = "--git-dir #{@location.shellescape}/.git" if @location
90
- branch = `git #{gitdir_option} rev-parse --abbrev-ref HEAD`.strip
91
-
92
- raise "Couldn't find current branch" if branch == 'HEAD'
93
-
94
- branch
81
+ def upstream?
82
+ @upstream
95
83
  end
96
84
 
97
85
  private
98
86
 
99
- # REPOSITORY METADATA
100
-
101
- # The result is in the format `git@github.com:donaldduck/geet.git`
102
- #
103
- def remote(name)
104
- gitdir_option = "--git-dir #{@location.shellescape}/.git" if @location
105
- remote_url = `git #{gitdir_option} ls-remote --get-url #{name}`.strip
106
-
107
- if remote_url == name
108
- raise "Remote #{name.inspect} not found!"
109
- elsif remote_url !~ REMOTE_ORIGIN_REGEX
110
- raise "Unexpected remote reference format: #{remote_url.inspect}"
111
- end
112
-
113
- remote_url
114
- end
115
-
116
- # "Lightweight" version of #remote.
117
- # Doesn't sanity check for the remote url format; this action is for querying
118
- # purposes, any any action that needs to work with the remote, uses #remote.
119
- #
120
- def has_remote?(name)
121
- gitdir_option = "--git-dir #{@location.shellescape}/.git" if @location
122
- remote_url = `git #{gitdir_option} ls-remote --get-url #{name}`.strip
123
-
124
- remote_url != name
125
- end
126
-
127
87
  # PROVIDER
128
88
 
129
89
  def extract_env_api_token
130
- env_variable_name = "#{provider_domain[/(.*)\.\w+/, 1].upcase}_API_TOKEN"
90
+ provider_name = @git_client.provider_domain[/(.*)\.\w+/, 1]
91
+ env_variable_name = "#{provider_name.upcase}_API_TOKEN"
131
92
 
132
93
  ENV[env_variable_name] || raise("#{env_variable_name} not set!")
133
94
  end
134
95
 
135
- def provider_domain
136
- # We assume that it's not possible to have origin and upstream on different providers.
137
- #
138
- remote_url = remote(ORIGIN_NAME)
139
-
140
- domain = remote_url[REMOTE_ORIGIN_REGEX, 1] || remote_url[REMOTE_ORIGIN_REGEX, 2]
141
-
142
- raise "Can't identify domain in the provider domain string: #{provider_domain}" if domain !~ /(.*)\.\w+/
143
-
144
- domain
145
- end
146
-
147
96
  # Attempt to find the provider class and send the specified method, returning a friendly
148
97
  # error (functionality X [Y] is missing) when a class/method is missing.
149
98
  def attempt_provider_call(class_name, meth, *args)
150
- module_name = provider_domain[/(.*)\.\w+/, 1].capitalize
99
+ module_name = provider_name.capitalize
151
100
 
152
101
  require_provider_modules
153
102
 
@@ -167,8 +116,7 @@ module Geet
167
116
  end
168
117
 
169
118
  def require_provider_modules
170
- provider_dirname = provider_domain[/(.*)\.\w+/, 1]
171
- files_pattern = "#{__dir__}/../#{provider_dirname}/*.rb"
119
+ files_pattern = "#{__dir__}/../#{provider_name}/*.rb"
172
120
 
173
121
  Dir[files_pattern].each { |filename| require filename }
174
122
  end
@@ -176,25 +124,23 @@ module Geet
176
124
  # OTHER HELPERS
177
125
 
178
126
  def api_interface
179
- attempt_provider_call(:ApiInterface, :new, @api_token, path(upstream: @upstream), @upstream)
180
- end
181
-
182
- # Example: `donaldduck/geet`
183
- #
184
- def path(upstream: false)
185
- remote_name = upstream ? UPSTREAM_NAME : ORIGIN_NAME
186
-
187
- remote(remote_name)[REMOTE_ORIGIN_REGEX, 3]
127
+ path = @git_client.path(upstream: @upstream)
128
+ attempt_provider_call(:ApiInterface, :new, @api_token, repo_path: path, upstream: @upstream)
188
129
  end
189
130
 
190
131
  def ask_confirm_action
191
- puts "WARNING! The action will be performed on a fork, but an upstream repository has been found!"
192
- print "Press Enter to continue, or Ctrl+C to exit now."
132
+ print CONFIRM_ACTION_TEXT.rstrip
193
133
  gets
194
134
  end
195
135
 
196
- def location_action_with_upstream_repository?
197
- has_remote?('upstream') && !@upstream
136
+ def local_action_with_upstream_repository?
137
+ @git_client.remote_defined?('upstream') && !@upstream
138
+ end
139
+
140
+ # Bare downcase provider name, eg. `github`
141
+ #
142
+ def provider_name
143
+ @git_client.provider_domain[/(.*)\.\w+/, 1]
198
144
  end
199
145
  end
200
146
  end