loca 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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