loca 0.0.1 → 0.1.0

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.
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - smoll
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-08 00:00:00.000000000 Z
11
+ date: 2015-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: addressable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.19.1
19
+ version: 2.3.7
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.19.1
26
+ version: 2.3.7
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: colorize
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,109 +53,123 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.0.1
55
55
  - !ruby/object:Gem::Dependency
56
- name: addressable
56
+ name: require_all
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 2.3.7
61
+ version: 1.3.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 2.3.7
68
+ version: 1.3.2
69
69
  - !ruby/object:Gem::Dependency
70
- name: bundler
70
+ name: aruba
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.6'
75
+ version: '0.6'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.6'
82
+ version: '0.6'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rake
84
+ name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.4'
90
- - - ">="
91
- - !ruby/object:Gem::Version
92
- version: 10.4.2
89
+ version: '1.7'
93
90
  type: :development
94
91
  prerelease: false
95
92
  version_requirements: !ruby/object:Gem::Requirement
96
93
  requirements:
97
94
  - - "~>"
98
95
  - !ruby/object:Gem::Version
99
- version: '10.4'
100
- - - ">="
96
+ version: '1.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: coveralls
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
101
102
  - !ruby/object:Gem::Version
102
- version: 10.4.2
103
+ version: 0.7.9
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.7.9
103
111
  - !ruby/object:Gem::Dependency
104
- name: rubocop
112
+ name: codeclimate-test-reporter
105
113
  requirement: !ruby/object:Gem::Requirement
106
114
  requirements:
107
115
  - - "~>"
108
116
  - !ruby/object:Gem::Version
109
- version: 0.29.0
117
+ version: 0.4.6
110
118
  type: :development
111
119
  prerelease: false
112
120
  version_requirements: !ruby/object:Gem::Requirement
113
121
  requirements:
114
122
  - - "~>"
115
123
  - !ruby/object:Gem::Version
116
- version: 0.29.0
124
+ version: 0.4.6
117
125
  - !ruby/object:Gem::Dependency
118
- name: rspec
126
+ name: rake
119
127
  requirement: !ruby/object:Gem::Requirement
120
128
  requirements:
121
129
  - - "~>"
122
130
  - !ruby/object:Gem::Version
123
- version: 3.2.0
131
+ version: '10.4'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 10.4.2
124
135
  type: :development
125
136
  prerelease: false
126
137
  version_requirements: !ruby/object:Gem::Requirement
127
138
  requirements:
128
139
  - - "~>"
129
140
  - !ruby/object:Gem::Version
130
- version: 3.2.0
141
+ version: '10.4'
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 10.4.2
131
145
  - !ruby/object:Gem::Dependency
132
- name: coveralls
146
+ name: rspec
133
147
  requirement: !ruby/object:Gem::Requirement
134
148
  requirements:
135
149
  - - "~>"
136
150
  - !ruby/object:Gem::Version
137
- version: 0.7.9
151
+ version: 3.2.0
138
152
  type: :development
139
153
  prerelease: false
140
154
  version_requirements: !ruby/object:Gem::Requirement
141
155
  requirements:
142
156
  - - "~>"
143
157
  - !ruby/object:Gem::Version
144
- version: 0.7.9
158
+ version: 3.2.0
145
159
  - !ruby/object:Gem::Dependency
146
- name: codeclimate-test-reporter
160
+ name: rubocop
147
161
  requirement: !ruby/object:Gem::Requirement
148
162
  requirements:
149
163
  - - "~>"
150
164
  - !ruby/object:Gem::Version
151
- version: 0.4.6
165
+ version: 0.30.1
152
166
  type: :development
153
167
  prerelease: false
154
168
  version_requirements: !ruby/object:Gem::Requirement
155
169
  requirements:
156
170
  - - "~>"
157
171
  - !ruby/object:Gem::Version
158
- version: 0.4.6
172
+ version: 0.30.1
159
173
  - !ruby/object:Gem::Dependency
160
174
  name: simplecov
161
175
  requirement: !ruby/object:Gem::Requirement
@@ -182,15 +196,21 @@ files:
182
196
  - lib/loca.rb
183
197
  - lib/loca/cli.rb
184
198
  - lib/loca/error.rb
185
- - lib/loca/git.rb
186
- - lib/loca/url.rb
199
+ - lib/loca/git/branch_creator.rb
200
+ - lib/loca/git/branch_deleter.rb
201
+ - lib/loca/git/common.rb
202
+ - lib/loca/url/parser.rb
203
+ - lib/loca/url/validator.rb
204
+ - lib/loca/utils.rb
187
205
  - lib/loca/version.rb
188
- - spec/e2e/github_spec.rb
189
206
  - spec/loca/cli_spec.rb
190
- - spec/loca/git_spec.rb
191
- - spec/loca/url_spec.rb
207
+ - spec/loca/git/branch_creator_spec.rb
208
+ - spec/loca/git/common_spec.rb
209
+ - spec/loca/url/parser_spec.rb
210
+ - spec/loca/url/validator_spec.rb
211
+ - spec/loca/utils_spec.rb
192
212
  - spec/spec_helper.rb
193
- - spec/support/features/github_helper.rb
213
+ - spec/support/matchers/terminate.rb
194
214
  homepage: https://github.com/smoll/loca
195
215
  licenses:
196
216
  - MIT
@@ -216,9 +236,11 @@ signing_key:
216
236
  specification_version: 4
217
237
  summary: CLI for checking out GitHub Pull Requests locally
218
238
  test_files:
219
- - spec/e2e/github_spec.rb
220
239
  - spec/loca/cli_spec.rb
221
- - spec/loca/git_spec.rb
222
- - spec/loca/url_spec.rb
240
+ - spec/loca/git/branch_creator_spec.rb
241
+ - spec/loca/git/common_spec.rb
242
+ - spec/loca/url/parser_spec.rb
243
+ - spec/loca/url/validator_spec.rb
244
+ - spec/loca/utils_spec.rb
223
245
  - spec/spec_helper.rb
224
- - spec/support/features/github_helper.rb
246
+ - spec/support/matchers/terminate.rb
@@ -1,117 +0,0 @@
1
- module Loca
2
- class Git
3
- include Thor::Actions
4
-
5
- attr_reader :branch_name
6
-
7
- def initialize(url, remote = nil)
8
- @url = Loca::URL.new(url)
9
- @branch_name = @url.branch_name
10
-
11
- ensure_git_repo
12
- ensure_no_unstashed_files
13
- @remote_name = remote || extract_remote_name
14
- end
15
-
16
- def delete
17
- # Cannot delete a branch you are currently on:
18
- checkout_another_branch if @branch_name == current_branch
19
- git "branch -D #{@branch_name}"
20
- end
21
-
22
- def checkout
23
- git "checkout #{@branch_name}", false # prints to stderr for some reason
24
- end
25
-
26
- def fetch
27
- # To avoid fatal error: Refusing to fetch into current branch
28
- delete unless first_time_creating?
29
- # Performs `git fetch upstream pull/PR_NUMBER/head:BRANCH_NAME`
30
- git "fetch #{@remote_name} pull/#{@url.pr_num}/head:#{@branch_name}", false # shellout has stderr for some reason
31
- end
32
-
33
- def first_time_creating? # Keep this a public method so we can prompt the user for overwrite
34
- branches.include?(@branch_name) ? false : true
35
- end
36
-
37
- # Example
38
- #
39
- # git_match_http?("https://github.com/smoll/loca.git", "https://github.com/smoll/loca/pull/1")
40
- # => true
41
- def git_match_http?(git, http)
42
- format = lambda do |uri| # Strip off uri scheme & trailing '.git'
43
- uri.sub('https://', '')
44
- .sub('http://', '')
45
- .sub('git://', '')
46
- .sub(/.git$/, '')
47
- end
48
- format.call(http).start_with?(format.call(git))
49
- end
50
-
51
- private
52
-
53
- def git(cmd, fail_on_stderr = true)
54
- shellout = Mixlib::ShellOut.new "git #{cmd}"
55
- shellout.run_command
56
- return shellout.stdout if shellout.stderr.empty?
57
- if fail_on_stderr
58
- fail Loca::Error::GitStdErrDetected, "#{shellout.stderr.strip}"
59
- else
60
- $stderr.puts shellout.stderr.strip.yellow
61
- end
62
- shellout.stdout.strip
63
- end
64
-
65
- def branches
66
- git("for-each-ref refs/heads/ --format='%(refname:short)'").split("\n")
67
- end
68
-
69
- def current_branch
70
- git('rev-parse --abbrev-ref HEAD').strip
71
- end
72
-
73
- def ensure_git_repo
74
- git 'rev-parse'
75
- end
76
-
77
- def ensure_no_unstashed_files
78
- val = git 'status --porcelain'
79
- fail Loca::Error::UnstashedFilesFound, 'Commit or stash your files before continuing!' unless val.empty?
80
- end
81
-
82
- def checkout_another_branch
83
- another = branches.find { |branch| branch != current_branch }
84
- fail Loca::Error::OnlyOneBranch, 'No other branch to checkout!' unless another
85
- git "checkout #{another}", false # prints to stderr for some reason
86
- end
87
-
88
- def remote_mapping
89
- names = git('remote show -n').split("\n")
90
- mapping = {}
91
- names.each do |name|
92
- mapping[name] = git("config --get remote.#{name}.url").strip
93
- end
94
- mapping
95
- end
96
-
97
- def extract_remote_name
98
- match = remote_mapping.find { |_name, url| git_match_http?(url, @url.to_s) }
99
- unless match
100
- if yes?("Remote #{(@url)} not set. Would you like to set it as 'auto_loca_remote'?")
101
- set_remote
102
- else
103
- fail Loca::Error::RemoteNotSet, "You must set the repo (#{@url}) as a remote "\
104
- "(see `git remote -v'). All remotes: #{remote_mapping}"
105
- end
106
- end
107
- match.first
108
- end
109
-
110
- def set_remote
111
- uri = Addressable::URI.parse(@url)
112
- uri.path = uri.path.split('/')[0..2].join('/')
113
- remote_url = "#{uri}.git"
114
- git "remote add upstream #{remote_url}"
115
- end
116
- end
117
- end
@@ -1,37 +0,0 @@
1
- module Loca
2
- class URL
3
- attr_reader :branch_name
4
- attr_reader :pr_num
5
-
6
- def initialize(url)
7
- @url = url
8
- ensure_well_formed
9
-
10
- @branch_name = extract_branch_name
11
- @pr_num = extract_pr_num
12
- end
13
-
14
- def to_s
15
- @url
16
- end
17
-
18
- def ensure_well_formed
19
- # TODO: add more checks via Addressable::URI
20
- segments = URI(@url).path.split('/')
21
- int = Integer(segments[-1]) rescue false # replace with coercible gem?
22
- pull = segments[-2] == 'pull'
23
-
24
- fail Loca::Error::InvalidURL, "Doesn't appear to be a well-formed URL: #{@url}" unless int && pull
25
- end
26
-
27
- private
28
-
29
- def extract_branch_name
30
- "PULL_#{extract_pr_num}"
31
- end
32
-
33
- def extract_pr_num
34
- URI(@url).path.split('/').last
35
- end
36
- end
37
- end
@@ -1,43 +0,0 @@
1
- describe 'Checking out a GitHub PR locally' do
2
- let(:pr_url) { 'https://github.com/octocat/Spoon-Knife/pull/4865' }
3
- let(:expected_branch_name) { 'PULL_4865' }
4
-
5
- before(:each) do
6
- clone_test_repo
7
- cd_to_cloned_dir
8
- end
9
-
10
- after(:each) { teardown }
11
-
12
- context "the repo exists as the 'upstream' remote" do
13
- before(:each) { set_upstream }
14
-
15
- it 'checks out then deletes' do
16
- shellout! "loca c #{pr_url}"
17
- expect(current_branch.strip).to eq expected_branch_name
18
- shellout! "loca c #{pr_url} -d"
19
- expect(current_branch.strip).to_not eq expected_branch_name
20
- end
21
-
22
- it 'checks out then prompts to overwrite' do
23
- shellout! "loca c #{pr_url}"
24
- expect(current_branch.strip).to eq expected_branch_name
25
- shellout! "loca c #{pr_url}", input: 'yes'
26
- expect(current_branch.strip).to eq expected_branch_name
27
- end
28
- end
29
-
30
- context 'the repo does not exist as a remote' do
31
- it 'fails to checkout' do
32
- expect { shellout! "loca c #{pr_url}" }.to raise_error
33
- expect(current_branch.strip).to_not eq expected_branch_name
34
- end
35
- end
36
-
37
- context 'the wrong URL is supplied' do
38
- it 'fails to checkout' do
39
- expect { shellout! 'loca c https://github.com/octocat/Spoon-Knife/wrong/4865' }.to raise_error
40
- expect(current_branch.strip).to_not eq expected_branch_name
41
- end
42
- end
43
- end
@@ -1,152 +0,0 @@
1
- describe Loca::Git do
2
- let(:pid) { 1 } # Pull request ID
3
- let(:url) { "https://github.com/smoll/loca/pull/#{pid}" }
4
- let(:remote_name) { 'loca-fake-remote' }
5
- let(:remote_url) { 'https://github.com/smoll/loca.git' }
6
- subject { described_class.new(url, remote_name) }
7
-
8
- let(:expected_branch_name) { "PULL_#{pid}" }
9
- let(:branches_without_expected) { ['master'] }
10
- let(:branches_with_expected) { branches_without_expected << expected_branch_name }
11
-
12
- describe '#git' do # private method that shells out to git
13
- it 'raises an error when an invalid git command is supplied' do
14
- expect { capture(:stderr) { subject.send(:git, 'not-a-git-command') } }.to raise_error
15
- end
16
-
17
- it 'prints to stderr when an invalid git command is supplied, but we do not want to fail on stderr' do
18
- output = capture(:stderr) { subject.send(:git, 'not-a-git-command', false) }
19
- expect(output).to include "git: 'not-a-git-command' is not a git command"
20
- end
21
- end
22
-
23
- describe '#branches' do # private method
24
- it 'returns all local branches' do
25
- cmd = "for-each-ref refs/heads/ --format='%(refname:short)'"
26
- expect(subject).to receive(:git).with(cmd).and_return 'a_branch'
27
- expect(subject.send(:branches)).to eq ['a_branch']
28
- end
29
- end
30
-
31
- describe '#remote_mapping' do # private method
32
- it "returns all of the repo's remotes" do
33
- expect(subject).to receive(:git).with('remote show -n').and_return remote_name
34
- expect(subject).to receive(:git).with("config --get remote.#{remote_name}.url").and_return remote_url
35
- expect(subject.send(:remote_mapping)).to eq(remote_name => remote_url)
36
- end
37
- end
38
-
39
- describe '#extract_remote_name' do # private method
40
- it 'returns the local repo remote name corresponding to the Pull Request URL' do
41
- expect(subject).to receive(:remote_mapping).and_return(remote_name => remote_url) # investigate this
42
-
43
- expect(subject.send(:extract_remote_name)).to eq remote_name
44
- end
45
- end
46
-
47
- describe '#current_branch' do # private method
48
- it 'returns the current branch' do
49
- expect(subject).to receive(:git).with('rev-parse --abbrev-ref HEAD').and_return "branch_name\n"
50
- expect(subject.send(:current_branch)).to eq 'branch_name'
51
- end
52
- end
53
-
54
- describe '#checkout' do # private method
55
- it 'checks out the expected branch' do
56
- expect(subject).to receive(:git).with("checkout #{expected_branch_name}", false).once
57
- subject.send(:checkout)
58
- end
59
- end
60
-
61
- describe '#checkout_another_branch' do # private method
62
- it 'checks out a branch that is not the current one' do
63
- allow(subject).to receive(:branches).and_return %w(branch1 branch2)
64
- allow(subject).to receive(:current_branch).and_return 'branch1'
65
- expect(subject).to receive(:git).with('checkout branch2', false).once
66
- silence(:stdout) { subject.send(:checkout_another_branch) }
67
- end
68
-
69
- it 'raises an error when there is no other branch to check out' do
70
- allow(subject).to receive(:branches).and_return ['branch1']
71
- allow(subject).to receive(:current_branch).and_return 'branch1'
72
-
73
- expect { silence(:stderr) { subject.send(:checkout_another_branch) } }.to raise_error
74
- end
75
- end
76
-
77
- describe '#fetch' do
78
- before do
79
- allow(subject).to receive(:git) # ensure we don't actually shell out to `git`
80
- end
81
-
82
- it 'deletes before fetching when the branch already exists' do
83
- allow(subject).to receive(:branches).and_return branches_with_expected
84
- expect(subject).to receive(:delete).once
85
-
86
- subject.fetch
87
- end
88
-
89
- it 'fetches the remote pull request' do
90
- allow(subject).to receive(:branches).and_return branches_without_expected
91
-
92
- # Investigate why this git command prints to $stderr, i.e. we must pass false as the 2nd arg:
93
- expect(subject).to receive(:git).with("fetch #{remote_name} pull/#{pid}/head:#{expected_branch_name}", false)
94
-
95
- subject.fetch
96
- end
97
- end
98
-
99
- describe '#delete' do # should attempt to delete a branch with name 'PULL_1'
100
- it 'raises an error when the branch does not exist' do
101
- allow(subject).to receive(:branches).and_return branches_without_expected
102
- expect { silence(:stderr) { subject.delete } }.to raise_error
103
- end
104
-
105
- it 'deletes the branch when it exists' do
106
- allow(subject).to receive(:branches).and_return branches_with_expected
107
- allow(subject).to receive(:current_branch).and_return('master')
108
- expect(subject).to receive(:git).with("branch -D #{expected_branch_name}").once
109
-
110
- subject.delete
111
- end
112
-
113
- it 'checks out another branch if attempting to delete current branch' do
114
- allow(subject).to receive(:branches).and_return branches_with_expected
115
- allow(subject).to receive(:current_branch).and_return expected_branch_name
116
-
117
- expect(subject).to receive(:checkout_another_branch).once
118
- expect(subject).to receive(:git).with("branch -D #{expected_branch_name}").once
119
-
120
- subject.delete
121
- end
122
- end
123
-
124
- describe '#first_time_creating?' do
125
- it 'returns false when the branch already exists' do
126
- allow(subject).to receive(:branches).and_return branches_with_expected
127
- expect(subject.first_time_creating?).to eq false
128
- end
129
-
130
- it 'returns true when the branch does not exist' do
131
- allow(subject).to receive(:branches).and_return branches_without_expected
132
- expect(subject.first_time_creating?).to eq true
133
- end
134
- end
135
-
136
- describe '#git_match_http?' do
137
- it 'returns true when matching urls are supplied' do
138
- git_url = 'https://github.com/smoll/loca.git'
139
- expect(subject.git_match_http?(git_url, url)).to eq true
140
- end
141
-
142
- it 'returns true when different URI schemes but matching urls are supplied' do
143
- git_url = 'git://github.com/smoll/loca.git'
144
- expect(subject.git_match_http?(git_url, url)).to eq true
145
- end
146
-
147
- it 'returns false when non-matching urls are supplied' do
148
- git_url = 'git://github.com/someoneelse/loca.git'
149
- expect(subject.git_match_http?(git_url, url)).to eq false
150
- end
151
- end
152
- end