git-browse-remote 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d53544ee6d46516eacca0cdffd3d41717e550c1
4
+ data.tar.gz: c4a7bcac64a6a4d730500c9b915cffca91a8abe5
5
+ SHA512:
6
+ metadata.gz: 50e226a70a929a512e1ae9d7bf24a9b16b2386a6f7f8c2b7d75c31e9485e056ba9fc8ce197e033895cfe7b7ce95d0551ba560b2470eabef510b910893c3a3016
7
+ data.tar.gz: 453d60928880551b838853267590d04879c8d81a123df8db78daa43ae8fbb0fa2635fa186d649ed620b62839e896ea2925fdbc77801ac260d5d4df06bc10fbc9
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git-browse-remote.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 motemen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ git-browse-remote [![Build Status](https://travis-ci.org/motemen/git-browse-remote.png?branch=master)](https://travis-ci.org/motemen/git-browse-remote)
2
+ =================
3
+
4
+ `git-browse-remote` helps viewing remote repositories e.g. GitHub in your browser.
5
+
6
+ Usage
7
+ -----
8
+
9
+ ```
10
+ git browse-remote [-r|--remote <remote>] [--top|--rev|--ref] [-L <n> [<commit> | <remote>] [<file>]
11
+ ```
12
+
13
+ `git-browse-remote` opens your web browser by `git web--browse` to show current repository in browser.
14
+
15
+ `git-browse-remote` depends on what commit/ref `HEAD` points (or you supplied by an argument), such as:
16
+
17
+ * When on "master", opens repository's top page ("top" mode)
18
+ * e.g. opens https://github.com/motemen/git-browse-remote
19
+ * When on another branch/tag, opens repository's branch/tag page ("ref" mode)
20
+ * e.g. opens https://github.com/motemen/git-browse-remote/tree/master
21
+ * Otherwise, opens repository's commit page ("rev" mode)
22
+ * e.g. opens https://github.com/motemen/git-browse-remote/commit/04f7c64ba9d524cf311a673ddce5722b2441e2ea
23
+
24
+ As a special case, if <var>commit</var> is invalid and an valid remote name, that remore repository's page is opened.
25
+
26
+ How to set up
27
+ -------------
28
+
29
+ `git browse-remote` stores url mapping in ~/.gitconfig.
30
+ To initialize this, execute with `--init` option.
31
+
32
+ ```
33
+ % git browse-remote --init
34
+ Writing config for github.com...
35
+ Mappings generated:
36
+ browse-remote.github.com.top https://{host}/{path}
37
+ browse-remote.github.com.ref https://{host}/{path}/tree/{short_ref}
38
+ browse-remote.github.com.rev https://{host}/{path}/commit/{commit}
39
+ browse-remote.github.com.file https://{host}/{path}/blob/{short_rev}/{file}{line && "#L%d" % line}
40
+ ```
41
+
42
+ Execute `git config browse-remote.<host>.{top|ref|rev} <url template>`
43
+ to register other hosts mappings.
44
+
45
+ Especially, if you have a GitHub Enterprise repository, run
46
+
47
+ ```
48
+ % git browse-remote --init <ghe host>=github
49
+ ```
50
+
51
+ to easyly setup url mappings. `--init <host>=gitweb` is also available.
52
+
53
+ Variables available in url template
54
+ -----------------------------------
55
+
56
+ * `host` (eg. "github.com")
57
+ * `path` (eg. "motemen/git-browse-remote")
58
+ * Sliceable, subscribable like an `Array`
59
+ * `ref` (eg. "refs/heads/master")
60
+ * `short_ref` (eg. "master")
61
+ * `commit` (eg. "04f7c64ba9d524cf311a673ddce5722b2441e2ea")
62
+ * `short_commit` (eg. "04f7c64b")
63
+ * `rev` (ref or commit)
64
+ * `short_rev` (short_ref or short_commit)
65
+ * `file` (eg. "bin/git-browse-remote")
66
+ * `line` (eg. 30)
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
@@ -1,146 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # USAGE:
4
- # git browse-remote [-r|--remote <remote>] [--top|--rev|--ref] [-L <n>] [<commit>] [<file>]
5
- #
3
+ require 'git/browse/remote'
6
4
 
7
- require 'optparse'
8
-
9
- class Path < Array
10
- def to_s
11
- join('/')
12
- end
13
- end
14
-
15
- remote = nil
16
- mode = nil
17
- file = nil
18
- line = nil
19
-
20
- # Variables available:
21
- # * host (eg. "github.com")
22
- # * path - Sliceable like an Array (eg. "motemen/git-browse-remote")
23
- # * ref (eg. "refs/heads/master")
24
- # * short_ref (eg. "master")
25
- # * commit (eg. "04f7c64ba9d524cf311a673ddce5722b2441e2ea")
26
- # * short_commit (eg. "04f7c64b")
27
- # * rev (ref or commit)
28
- # * short_rev (short_ref or short_commit)
29
- # * file (eg. "bin/git-browse-remote")
30
- # * line (eg. 30)
31
- MAPPING_RECIPES = {
32
- :github => {
33
- :top => 'https://{host}/{path}',
34
- :ref => 'https://{host}/{path}/tree/{short_ref}',
35
- :rev => 'https://{host}/{path}/commit/{commit}',
36
- :file => 'https://{host}/{path}/blob/{short_rev}/{file}{line && "#L%d" % line}'
37
- },
38
-
39
- :gitweb => {
40
- :top => 'http://{host}/?p={path[-2..-1]}.git',
41
- :ref => 'http://{host}/?p={path[-2..-1]}.git;h={ref}',
42
- :rev => 'http://{host}/?p={path[-2..-1]}.git;a=commit;h={ref}',
43
- # XXX
44
- # I don't know file url of gitweb...
45
- }
46
- }
47
-
48
- OptionParser.new do |opt|
49
- opt.banner = 'git browse-remote [options] [<commit> | <remote>]'
50
- opt.on('-r', '--remote=<remote>', 'specify remote') { |r| remote = r }
51
-
52
- opt.on('--top', 'open `top` page') { mode = :top }
53
- opt.on('--rev', 'open `rev` page') { mode = :rev }
54
- opt.on('--ref', 'open `ref` page') { mode = :ref }
55
- opt.on('--init [<host>=<recipe>]', 'initialize default url mappings') do |config|
56
- if config
57
- host, name = *config.split(/=/, 2)
58
- else
59
- host, name = 'github.com', 'github'
60
- end
61
-
62
- STDERR.puts "Writing config for #{host}..."
63
-
64
- mapping = MAPPING_RECIPES[name.to_sym] or abort "Recipe '#{name}' not found"
65
- mapping.each do |mode,template|
66
- system %Q(git config --global browse-remote.#{host}.#{mode} '#{template}')
67
- end
68
-
69
- STDERR.puts 'Mappings generated:'
70
- exec "git config --get-regexp ^browse-remote\\.#{host}\\."
71
- end
72
- opt.on('-L <n>', 'specify line number (only meaningful on file mode)', Integer) { |n| line = n }
73
- opt.parse!(ARGV)
74
- end
75
-
76
- target, file = *ARGV[0..1]
77
-
78
- # handle git browse-remote <file>
79
- # TODO file exists and also is a valid ref/origin
80
- if target && !file && File.exists?(target)
81
- target, file = nil, target
82
- end
83
-
84
- target ||= `git symbolic-ref -q HEAD`[/.+/]
85
-
86
- if target
87
- if `git rev-parse --verify --quiet #{target}` && $? == 0
88
- # valid ref
89
- ref = `git rev-parse --symbolic-full-name #{target}`.chomp
90
- elsif `git config --get remote.#{target}.url`.chomp.empty? == false
91
- # not a valid ref, but valid remote
92
- ref = 'master'
93
- remote = target
94
- target = nil
95
- else
96
- abort "Not a valid ref or remote: #{target}"
97
- end
98
- else
99
- ref = `git name-rev --name-only HEAD`.chomp.sub(%r(\^0$), '') # some workaround for ^0
100
- end
101
-
102
- if ref == 'HEAD'
103
- ref = nil
104
- short_ref = nil
105
- else
106
- short_ref = ref.sub(%r(^refs/), '')
107
-
108
- if short_ref.sub!(%r(^heads/), '')
109
- mode ||= short_ref == 'master' ? :top : :ref
110
- end
111
-
112
- if short_ref.sub!(%r(^tags/), '')
113
- mode ||= :ref
114
- end
115
-
116
- if short_ref.sub!(%r(^remotes/([^/]+)/), '')
117
- remote ||= $1
118
- mode ||= short_ref == 'master' ? :top : :ref
119
- end
120
-
121
- end
122
-
123
- commit = `git rev-parse #{target || 'HEAD'}`.chomp
124
- short_commit = `git rev-parse --short #{target || 'HEAD'}`.chomp
125
-
126
- # `rev` will be raw sha1 if --rev is specified explicitly
127
- rev = mode == :rev ? commit : ref || commit
128
- short_rev = mode == :rev ? short_commit : short_ref || short_commit
129
-
130
- mode = :file if file
131
-
132
- remote ||= 'origin'
133
- mode ||= :rev
134
-
135
- remote_url = `git config remote.#{remote}.url`[/.+/] or
136
- abort "Could not get remote url: #{remote}"
137
-
138
- host, *path = remote_url.sub(%r(^\w+://), '').sub(/^[\w-]+@/, '').split(/[\/:]+/)
139
- path.last.sub!(/\.git$/, '')
140
- path = Path.new(path)
141
-
142
- template = `git config --get browse-remote.#{host}.#{mode}`[/.+/] or
143
- abort "No '#{mode}' mapping found for #{host} (maybe `git browse-remote --init` required)"
144
-
145
- url = template.gsub(/\{(.+?)\}/) { |m| eval($1) }
146
- exec 'git', 'web--browse', url
5
+ Git::Browse::Remote::Runner.new(ARGV).run
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git/browse/remote/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-browse-remote"
8
+ spec.version = Git::Browse::Remote::VERSION
9
+ spec.authors = ["motemen"]
10
+ spec.email = ["motemen@gmail.com"]
11
+ spec.summary = 'Open web browser to view remote Git repositories'
12
+ spec.homepage = 'https://github.com/motemen/git-browse-remote'
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake"
22
+ spec.add_development_dependency 'rspec', '~> 2'
23
+ spec.add_development_dependency 'simplecov', '0.7.1'
24
+ spec.add_development_dependency 'guard'
25
+ spec.add_development_dependency 'guard-rspec'
26
+ spec.add_development_dependency 'terminal-notifier-guard'
27
+ end
@@ -0,0 +1,2 @@
1
+ require 'git/browse/remote/version'
2
+ require 'git/browse/remote/runner'
@@ -0,0 +1,176 @@
1
+ require 'git/browse/remote/git'
2
+
3
+ module Git::Browse::Remote
4
+ class Path < Array
5
+ def to_s
6
+ join('/')
7
+ end
8
+ end
9
+
10
+ class Core
11
+ attr_accessor :line, :file
12
+
13
+ MAPPING_RECIPES = {
14
+ :github => {
15
+ :top => 'https://{host}/{path}',
16
+ :ref => 'https://{host}/{path}/tree/{short_ref}',
17
+ :rev => 'https://{host}/{path}/commit/{commit}',
18
+ :file => 'https://{host}/{path}/blob/{short_rev}/{file}{line && "#L%d" % line}'
19
+ },
20
+
21
+ :gitweb => {
22
+ :top => 'http://{host}/?p={path[-2..-1]}.git',
23
+ :ref => 'http://{host}/?p={path[-2..-1]}.git;h={ref}',
24
+ :rev => 'http://{host}/?p={path[-2..-1]}.git;a=commit;h={ref}',
25
+ # XXX
26
+ # I don't know file url of gitweb...
27
+ }
28
+ }
29
+
30
+ def template_type
31
+ if @file
32
+ :file
33
+ else
34
+ mode
35
+ end
36
+ end
37
+
38
+ def init!(host, name)
39
+ mapping = MAPPING_RECIPES[name] or abort "Recipe '#{name}' not found"
40
+ mapping.each do |mode,template|
41
+ system %Q(git config --global browse-remote.#{host}.#{mode} '#{template}')
42
+ end
43
+ end
44
+
45
+ def url
46
+ if target && !@file && File.exists?(target)
47
+ self.target, @file = nil, target
48
+ end
49
+
50
+ if target
51
+ if Git.is_valid_rev? target
52
+ @ref = Git.full_name_of_rev(target)
53
+ elsif Git.is_valid_remote? target
54
+ @remote, @ref = target, 'master'
55
+ else
56
+ abort "Not a valid ref or remote: #{target}"
57
+ end
58
+ else
59
+ @ref = Git.symbolic_name_of_head
60
+ end
61
+
62
+ if @ref == 'HEAD'
63
+ @ref = nil
64
+ end
65
+
66
+ remote_url = `git config remote.#{remote}.url`[/.+/] or
67
+ abort "Could not get remote url: #{remote}"
68
+
69
+ host, *path = remote_url.sub(%r(^\w+://), '').sub(/^[\w-]+@/, '').split(/[\/:]+/)
70
+ path.last.sub!(/\.git$/, '')
71
+ path = Path.new(path)
72
+
73
+ template = `git config --get browse-remote.#{host}.#{template_type}`[/.+/]
74
+ if not template and host == 'github.com'
75
+ template = MAPPING_RECIPES[:github][template_type.to_sym] or
76
+ abort "No '#{template_type}' mapping found for #{host} (maybe `git browse-remote --init` required)"
77
+ end
78
+
79
+ url = template.gsub(/\{(.+?)\}/) { |m| eval($1) }
80
+ end
81
+
82
+ def remote=(remote)
83
+ @remote = remote
84
+ end
85
+
86
+ def remote
87
+ return @remote if @remote
88
+
89
+ if ref
90
+ if ref.match(%r<^(?:refs/)?remotes/([^/]+)/>)
91
+ @remote = $1
92
+ end
93
+ end
94
+
95
+ @remote ||= 'origin'
96
+ end
97
+
98
+ def mode=(mode)
99
+ @mode = mode
100
+ end
101
+
102
+ def mode
103
+ return @mode if @mode
104
+
105
+ if ref
106
+ if ref.match(%r<^((?:refs/)?(?:heads|remotes/[^/]+)/)?master$>)
107
+ @mode = :top
108
+ elsif ref.match(%r<^(?:refs/)?(?:heads|tags|remotes)/>)
109
+ @mode = :ref
110
+ end
111
+ end
112
+
113
+ @mode || :rev
114
+ end
115
+
116
+ def _commit(short = false)
117
+ if short
118
+ Git.parse_rev_short(target || 'HEAD')
119
+ else
120
+ Git.parse_rev(target || 'HEAD')
121
+ end
122
+ end
123
+
124
+ def commit
125
+ _commit
126
+ end
127
+
128
+ def short_commit
129
+ _commit(true)
130
+ end
131
+
132
+ def _rev(short = false)
133
+ if mode == :rev
134
+ _commit(short)
135
+ else
136
+ _ref(short) || _commit(short)
137
+ end
138
+ end
139
+
140
+ def rev
141
+ _rev
142
+ end
143
+
144
+ def short_rev
145
+ _rev(true)
146
+ end
147
+
148
+ def _ref(short = false)
149
+ if short
150
+ @ref.sub(%r(^refs/), '').
151
+ sub(%r(^heads/), '').
152
+ sub(%r(^tags/), '').
153
+ sub(%r(^remotes/([^/]+)/), '')
154
+ else
155
+ @ref
156
+ end
157
+ end
158
+
159
+ def ref
160
+ _ref
161
+ end
162
+
163
+ def short_ref
164
+ _ref(true)
165
+ end
166
+
167
+ def target=(target)
168
+ @target = target
169
+ end
170
+
171
+ def target
172
+ return @target if @target
173
+ @target ||= Git.resolved_head
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,36 @@
1
+ module Git::Browse::Remote
2
+ module Git
3
+ def self.is_valid_rev?(target)
4
+ `git rev-parse --verify --quiet #{target}` && $? == 0
5
+ end
6
+
7
+ def self.is_valid_remote?(remote)
8
+ `git config --get remote.#{remote}.url`.chomp.empty? == false
9
+ end
10
+
11
+ def self.parse_rev(ref)
12
+ `git rev-parse #{ref}`.chomp
13
+ end
14
+
15
+ def self.parse_rev_short(ref)
16
+ `git rev-parse --short #{ref}`.chomp
17
+ end
18
+
19
+ def self.full_name_of_rev(rev)
20
+ `git rev-parse --symbolic-full-name #{rev}`[/.+/] or `git rev-parse --symbolic-full-name #{name_rev(rev)}`[/.+/]
21
+ end
22
+
23
+ # the ref whom HEAD points to
24
+ def self.resolved_head
25
+ `git symbolic-ref -q HEAD`[/.+/]
26
+ end
27
+
28
+ def self.name_rev(rev)
29
+ `git name-rev --name-only #{rev}`.chomp
30
+ end
31
+
32
+ def self.symbolic_name_of_head
33
+ name_rev('HEAD').sub(%r(\^0$), '') # some workaround for ^0
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ require 'git/browse/remote/core'
2
+ require 'git/browse/remote/version'
3
+ require 'optparse'
4
+
5
+ module Git::Browse::Remote
6
+ class Runner
7
+ def initialize(args)
8
+ @args = args
9
+ @core = Core.new
10
+ end
11
+
12
+ def run
13
+ OptionParser.new do |opt|
14
+ opt.banner = 'git browse-remote [options] [<commit> | <remote>] [--] [<file>]'
15
+ opt.version = VERSION
16
+ opt.on('-r', '--remote=<remote>', 'specify remote') { |r| @core.remote = r }
17
+
18
+ opt.on('--stdout', 'prints URL instead of opening browser') { @stdout = true }
19
+
20
+ opt.on('--top', 'open `top` page') { @core.mode = :top }
21
+ opt.on('--rev', 'open `rev` page') { @core.mode = :rev }
22
+ opt.on('--ref', 'open `ref` page') { @core.mode = :ref }
23
+ opt.on('--init [<host>=<recipe>]', 'initialize default url mappings') do |config|
24
+ if config
25
+ host, name = *config.split(/=/, 2)
26
+ else
27
+ host, name = 'github.com', 'github'
28
+ end
29
+
30
+ STDERR.puts "Writing config for #{host}..."
31
+
32
+ @core.init!(host, name.to_sym)
33
+
34
+ STDERR.puts 'Mappings generated:'
35
+ exec "git config --get-regexp ^browse-remote\\.#{host}\\."
36
+ end
37
+ opt.on('-L <n>', 'specify line number (only meaningful on file mode)', Integer) { |n| @core.line = n }
38
+ end.parse!(@args)
39
+
40
+ @core.target, @core.file = *@args[0..1]
41
+
42
+ if @stdout
43
+ puts @core.url
44
+ else
45
+ exec 'git', 'web--browse', @core.url
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ module Git
2
+ module Browse
3
+ module Remote
4
+ VERSION = '0.0.3'
5
+ end
6
+ end
7
+ end
data/spec/bin_spec.rb ADDED
@@ -0,0 +1,333 @@
1
+ require 'rspec'
2
+ require 'tmpdir'
3
+ require 'pathname'
4
+ require 'open3'
5
+
6
+ unless ENV['CI']
7
+ require 'simplecov'
8
+
9
+ module SimpleCov
10
+ def self.lap
11
+ if running
12
+ @result = SimpleCov::Result.new(Coverage.result.merge_resultset(SimpleCov::ResultMerger.merged_result.original_result))
13
+ SimpleCov::ResultMerger.store_result(@result)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ ROOT = Pathname.new(__FILE__).parent.parent
20
+
21
+ $:.unshift ROOT.join('lib').to_s
22
+
23
+ require 'git/browse/remote'
24
+
25
+ def git(*args)
26
+ if Open3.methods(false).include? :capture3
27
+ out, err, status = Open3.capture3('git', *args.map { |arg| arg.to_s })
28
+ else
29
+ out = `git #{args.map { |arg| arg.to_s.shellescape }.join(' ')}`
30
+ status = $?.to_i
31
+ end
32
+
33
+ if status != 0
34
+ abort "git #{args.join(' ')} failed: #{err}"
35
+ end
36
+
37
+ out[/.*/]
38
+ end
39
+
40
+ RSpec.configure do |config|
41
+ config.before(:all) do
42
+ @pwd = Dir.pwd
43
+ @tmpdir = Dir.mktmpdir
44
+ Dir.chdir @tmpdir
45
+
46
+ @sha1 = {}
47
+
48
+ git :init
49
+
50
+ git :config, '--local', 'user.email', 'gbr@example.com'
51
+ git :config, '--local', 'user.name', 'git-browse-remote tester'
52
+
53
+ git :remote, 'add', 'origin', 'https://github.com/user/repo.git'
54
+ git :remote, 'add', 'origin2', 'git@gh-mirror.host:user/repo2'
55
+
56
+ FileUtils.copy_file ROOT + 'README.md', 'README.md'
57
+ git :add, 'README.md'
58
+ git :commit, '-m' '1st commit'
59
+
60
+ git :commit, '-m' '2nd commit', '--allow-empty'
61
+
62
+ git :checkout, '-b', 'branch-1'
63
+
64
+ git :commit, '-m' 'branched commit', '--allow-empty'
65
+ @sha1[:'branch-1'] = git 'rev-parse', 'HEAD'
66
+
67
+ git :checkout, 'master'
68
+
69
+ git :commit, '-m' '3rd commit (tagged)', '--allow-empty'
70
+ git :tag, 'tag-a'
71
+
72
+ git :commit, '-m' '4th commit (remote HEAD)', '--allow-empty'
73
+ git :remote, 'add', 'local-remote', '.git'
74
+ git :remote, 'update', 'local-remote'
75
+ git :remote, 'set-url', 'local-remote', 'https://github.com/user/repo3.git'
76
+
77
+ git :commit, '-m' '5th commit', '--allow-empty'
78
+ @sha1[:'master~1'] = git 'rev-parse', 'HEAD'
79
+
80
+ git :commit, '-m' '6th commit', '--allow-empty'
81
+ @sha1[:master] = git 'rev-parse', 'HEAD'
82
+
83
+ # system 'git log --abbrev-commit --oneline --decorate --graph --all'
84
+ # the commit graph looks like below;
85
+ #
86
+ # * e6b5d6f (local-remote/branch-1, branch-1) branched commit
87
+ # | * 03b1d4d (HEAD, master) 6th commit
88
+ # | * b591899 5th commit
89
+ # | * 3139e94 (local-remote/master) 4th commit (remote HEAD)
90
+ # | * a423770 (tag: tag-a) 3rd commit (tagged)
91
+ # |/
92
+ # * 06f6ebb 2nd commit
93
+ # * ff7b92b 1st commit
94
+ end
95
+
96
+ config.after(:all) do
97
+ FileUtils.remove_entry @tmpdir
98
+ Dir.chdir @pwd
99
+ end
100
+
101
+ config.after(:each) do
102
+ git :checkout, 'master'
103
+ end
104
+ end
105
+
106
+ module Kernel
107
+ def exec(*args)
108
+ $exec_args = args
109
+ end
110
+ end
111
+
112
+ def git_browse_remote(args)
113
+ begin
114
+ SimpleCov.start unless ENV['CI']
115
+ ARGV.replace(args)
116
+ load ROOT + 'bin/git-browse-remote', true
117
+ true
118
+ rescue
119
+ false
120
+ ensure
121
+ SimpleCov.lap unless ENV['CI']
122
+ end
123
+ end
124
+
125
+ def opened_url
126
+ git_browse_remote(args)
127
+
128
+ if $exec_args[0..1] == [ 'git', 'web--browse' ]
129
+ $exec_args[2]
130
+ else
131
+ nil
132
+ end
133
+ end
134
+
135
+ def when_run_with_args(*args, &block)
136
+ context "when run with args #{args}" do
137
+ let(:args) { args }
138
+ instance_eval(&block)
139
+ end
140
+ end
141
+
142
+ describe 'git-browse-remote' do
143
+ when_run_with_args '--init', 'gh-mirror.host=github' do
144
+ it 'should run successfully' do
145
+ expect(git_browse_remote(args)).to be(true)
146
+ end
147
+ end
148
+
149
+ context 'when on master' do
150
+ when_run_with_args do
151
+ it 'should open top page' do
152
+ expect(opened_url).to eq("https://github.com/user/repo")
153
+ end
154
+ end
155
+
156
+ when_run_with_args '--top' do
157
+ it 'should open top page' do
158
+ expect(opened_url).to eq("https://github.com/user/repo")
159
+ end
160
+ end
161
+
162
+ when_run_with_args '--rev' do
163
+ it 'should open rev page' do
164
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:master]}")
165
+ end
166
+ end
167
+
168
+ when_run_with_args '--ref' do
169
+ it 'should open ref page' do
170
+ expect(opened_url).to eq("https://github.com/user/repo/tree/master")
171
+ end
172
+ end
173
+
174
+ when_run_with_args 'HEAD~1' do
175
+ it 'should open previous rev\'s page' do
176
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:'master~1']}")
177
+ end
178
+ end
179
+
180
+ when_run_with_args 'master' do
181
+ it 'should open top page' do
182
+ expect(opened_url).to eq("https://github.com/user/repo")
183
+ end
184
+ end
185
+
186
+ when_run_with_args '--', 'README.md' do
187
+ it 'should open the file page' do
188
+ expect(opened_url).to eq("https://github.com/user/repo/blob/master/README.md")
189
+ end
190
+ end
191
+
192
+ when_run_with_args '--rev', '--', 'README.md' do
193
+ it 'should open the file page by revision' do
194
+ expect(opened_url).to eq("https://github.com/user/repo/blob/#{@sha1[:master][0..6]}/README.md")
195
+ end
196
+ end
197
+
198
+ when_run_with_args '-L3', '--', 'README.md' do
199
+ it 'should open the file at the specified line' do
200
+ expect(opened_url).to eq("https://github.com/user/repo/blob/master/README.md#L3")
201
+ end
202
+ end
203
+
204
+ when_run_with_args 'branch-1' do
205
+ it 'should open the branch page' do
206
+ expect(opened_url).to eq("https://github.com/user/repo/tree/branch-1")
207
+ end
208
+ end
209
+
210
+ when_run_with_args '--rev', 'branch-1' do
211
+ it 'should open the rev page of the branch' do
212
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:'branch-1']}")
213
+ end
214
+ end
215
+
216
+ when_run_with_args '--remote', 'origin2' do
217
+ it 'should open the specified remote page' do
218
+ expect(opened_url).to eq("https://gh-mirror.host/user/repo2")
219
+ end
220
+ end
221
+
222
+ when_run_with_args '-r', 'origin2' do
223
+ it 'should open the specified remote page' do
224
+ expect(opened_url).to eq("https://gh-mirror.host/user/repo2")
225
+ end
226
+ end
227
+
228
+ when_run_with_args '-r', 'origin2', '--rev' do
229
+ it 'should open the specified remote page and the revision' do
230
+ expect(opened_url).to eq("https://gh-mirror.host/user/repo2/commit/#{@sha1[:master]}")
231
+ end
232
+ end
233
+
234
+ when_run_with_args 'README.md' do
235
+ it 'should open file file page' do
236
+ expect(opened_url).to eq("https://github.com/user/repo/blob/master/README.md")
237
+ end
238
+ end
239
+
240
+ when_run_with_args 'origin2' do
241
+ it 'should open the remote' do
242
+ expect(opened_url).to eq("https://gh-mirror.host/user/repo2")
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'on some branch' do
248
+ before { git :checkout, 'branch-1' }
249
+
250
+ when_run_with_args do
251
+ it 'should open the current branch page' do
252
+ expect(opened_url).to eq("https://github.com/user/repo/tree/branch-1")
253
+ end
254
+ end
255
+
256
+ when_run_with_args '--top' do
257
+ it 'should open the top page' do
258
+ expect(opened_url).to eq("https://github.com/user/repo")
259
+ end
260
+ end
261
+
262
+ when_run_with_args '--rev' do
263
+ it 'should open the revision page of current HEAD' do
264
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:'branch-1']}")
265
+ end
266
+ end
267
+
268
+ when_run_with_args 'README.md' do
269
+ it 'should open the file page at current branch' do
270
+ expect(opened_url).to eq("https://github.com/user/repo/blob/branch-1/README.md")
271
+ end
272
+ end
273
+ end
274
+
275
+ context 'on detached HEAD' do
276
+ before { git :checkout, 'HEAD~1' }
277
+
278
+ when_run_with_args do
279
+ it 'should open the revision page' do
280
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:'master~1']}")
281
+ end
282
+ end
283
+
284
+ when_run_with_args 'HEAD' do
285
+ it 'should open the revision page' do
286
+ expect(opened_url).to eq("https://github.com/user/repo/commit/#{@sha1[:'master~1']}")
287
+ end
288
+ end
289
+ end
290
+
291
+ context 'on tag' do
292
+ before { git :checkout, 'tag-a' }
293
+
294
+ when_run_with_args do
295
+ it 'should open the tag page' do
296
+ expect(opened_url).to eq("https://github.com/user/repo/tree/tag-a")
297
+ end
298
+ end
299
+ end
300
+
301
+ context 'on remote branch' do
302
+ before { git :checkout, 'local-remote/master' }
303
+
304
+ when_run_with_args do
305
+ it 'should open the remote' do
306
+ expect(opened_url).to eq("https://github.com/user/repo3")
307
+ end
308
+ end
309
+ end
310
+
311
+ context 'after changing branches' do
312
+ before {
313
+ git :checkout, 'branch-1'
314
+ git :checkout, 'master'
315
+ }
316
+
317
+ when_run_with_args 'HEAD@{1}' do
318
+ it 'should open the previous branch page' do
319
+ expect(opened_url).to eq("https://github.com/user/repo/tree/branch-1")
320
+ end
321
+ end
322
+
323
+ when_run_with_args '--ref', 'HEAD@{1}' do
324
+ it 'should open the previous branch page' do
325
+ expect(opened_url).to eq("https://github.com/user/repo/tree/branch-1")
326
+ end
327
+ end
328
+ end
329
+
330
+ it 'should abort on invalid ref' do
331
+ expect { git_browse_remote([ 'xxx-nonexistent-ref' ]) }.to raise_error SystemExit
332
+ end
333
+ end
@@ -0,0 +1,159 @@
1
+ require 'git/browse/remote/core'
2
+
3
+ describe Git::Browse::Remote::Core do
4
+ subject(:core) { Git::Browse::Remote::Core.new }
5
+
6
+ describe '#template_type' do
7
+ context 'if @file set' do
8
+ before { core.file = 'README.md' }
9
+
10
+ it 'is :file' do
11
+ expect(core.template_type).to be(:file)
12
+ end
13
+ end
14
+
15
+ context 'if @file not set' do
16
+ it 'is same as #mode' do
17
+ expect(core.template_type).to be(core.mode)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#remote' do
23
+ context 'by default' do
24
+ it 'is "origin"' do
25
+ expect(core.remote).to eq('origin')
26
+ end
27
+ end
28
+
29
+ context 'if remote set' do
30
+ before { core.remote = 'remote-foo' }
31
+
32
+ it 'is the set value' do
33
+ expect(core.remote).to eq('remote-foo')
34
+ end
35
+ end
36
+
37
+ context 'if #ref is a remote ref' do
38
+ it 'is the remote name in the ref' do
39
+ core.stub(:ref).and_return('remotes/remote-bar/master')
40
+ expect(core.remote).to eq('remote-bar')
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#mode' do
46
+ context 'by default' do
47
+ it 'is :rev' do
48
+ expect(core.mode).to eq(:rev)
49
+ end
50
+ end
51
+
52
+ context 'if mode set' do
53
+ before { core.mode = :foo }
54
+
55
+ it 'is the set value' do
56
+ expect(core.mode).to eq(:foo)
57
+ end
58
+ end
59
+
60
+ context 'if #ref points to master' do
61
+ it 'is :top' do
62
+ core.stub(:ref).and_return('refs/heads/master')
63
+ expect(core.mode).to eq(:top)
64
+ end
65
+ end
66
+
67
+ context 'if #ref points to some ref' do
68
+ it 'is :ref' do
69
+ core.stub(:ref).and_return('refs/heads/branch-a')
70
+ expect(core.mode).to eq(:ref)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#commit' do
76
+ it 'calls Git.parse_rev with #target' do
77
+ Git::Browse::Remote::Git.should_receive(:parse_rev).with('__TARGET__').and_return('0000000000000000000000000000000000000000')
78
+ core.stub(:target).and_return('__TARGET__')
79
+ expect(core.commit).to eq('0000000000000000000000000000000000000000')
80
+ end
81
+ end
82
+
83
+ describe '#short_commit' do
84
+ it 'calls Git.parse_rev_short with #target' do
85
+ Git::Browse::Remote::Git.should_receive(:parse_rev_short).with('__TARGET__').and_return('00000000')
86
+ core.stub(:target).and_return('__TARGET__')
87
+ expect(core.short_commit).to eq('00000000')
88
+ end
89
+ end
90
+
91
+ describe '#_rev' do
92
+ context 'if #mode is :ref (not :rev)' do
93
+ before { core.stub(:mode).and_return(:ref) }
94
+
95
+ context 'and #_ref is not defined' do
96
+ it 'returns the #_commit value' do
97
+ core.should_receive(:_commit).and_return('0000000000000000000000000000000000000000')
98
+ expect(core._rev).to eq('0000000000000000000000000000000000000000')
99
+ end
100
+ end
101
+
102
+ context 'and #_ref is defined' do
103
+ it 'returns the #_ref value' do
104
+ core.should_receive(:_ref).and_return('a-ref')
105
+ expect(core._rev).to eq('a-ref')
106
+ end
107
+ end
108
+ end
109
+
110
+ context 'if #mode is :rev' do
111
+ before { core.stub(:mode).and_return(:rev) }
112
+
113
+ context 'and #_ref is not defined' do
114
+ it 'returns the #_commit value' do
115
+ core.should_receive(:_commit).and_return('0000000000000000000000000000000000000000')
116
+ expect(core._rev).to eq('0000000000000000000000000000000000000000')
117
+ end
118
+ end
119
+
120
+ context 'and #_ref is defined' do
121
+ it 'returns the #_commit value though' do
122
+ core.stub(:_ref).and_return('a-ref')
123
+ core.should_receive(:_commit).and_return('0000000000000000000000000000000000000000')
124
+ expect(core._rev).to eq('0000000000000000000000000000000000000000')
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ describe '#short_ref' do
131
+ context 'if @ref is "refs/heads/master"' do
132
+ before { core.instance_variable_set :@ref, 'refs/heads/master' }
133
+ it 'should be "master"' do
134
+ expect(core.short_ref).to eq('master')
135
+ end
136
+ end
137
+
138
+ context 'if @ref is "refs/heads/fix/some/bug"' do
139
+ before { core.instance_variable_set :@ref, 'refs/heads/fix/some/bug' }
140
+ it 'should be "fix/some/bug"' do
141
+ expect(core.short_ref).to eq('fix/some/bug')
142
+ end
143
+ end
144
+
145
+ context 'if @ref is "refs/tags/v0.0.1"' do
146
+ before { core.instance_variable_set :@ref, 'refs/tags/v0.0.1' }
147
+ it 'should be "v0.0.1"' do
148
+ expect(core.short_ref).to eq('v0.0.1')
149
+ end
150
+ end
151
+
152
+ context 'if @ref is "refs/remotes/origin/foo/bar"' do
153
+ before { core.instance_variable_set :@ref, 'refs/remotes/origin/foo/bar' }
154
+ it 'should be "foo/bar"' do
155
+ expect(core.short_ref).to eq('foo/bar')
156
+ end
157
+ end
158
+ end
159
+ end
metadata CHANGED
@@ -1,47 +1,162 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-browse-remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
5
- prerelease:
4
+ version: 0.0.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - motemen
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-10-05 00:00:00.000000000 Z
13
- dependencies: []
11
+ date: 2013-10-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.7.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.7.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: terminal-notifier-guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
14
111
  description:
15
- email: motemen@gmail.com
112
+ email:
113
+ - motemen@gmail.com
16
114
  executables:
17
115
  - git-browse-remote
18
116
  extensions: []
19
117
  extra_rdoc_files: []
20
118
  files:
119
+ - .gitignore
120
+ - .travis.yml
121
+ - Gemfile
122
+ - Guardfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
21
126
  - bin/git-browse-remote
127
+ - git-browse-remote.gemspec
128
+ - lib/git/browse/remote.rb
129
+ - lib/git/browse/remote/core.rb
130
+ - lib/git/browse/remote/git.rb
131
+ - lib/git/browse/remote/runner.rb
132
+ - lib/git/browse/remote/version.rb
133
+ - spec/bin_spec.rb
134
+ - spec/lib/git/browse/remote/core_spec.rb
22
135
  homepage: https://github.com/motemen/git-browse-remote
23
- licenses: []
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
24
139
  post_install_message:
25
140
  rdoc_options: []
26
141
  require_paths:
27
142
  - lib
28
143
  required_ruby_version: !ruby/object:Gem::Requirement
29
- none: false
30
144
  requirements:
31
- - - ! '>='
145
+ - - '>='
32
146
  - !ruby/object:Gem::Version
33
147
  version: '0'
34
148
  required_rubygems_version: !ruby/object:Gem::Requirement
35
- none: false
36
149
  requirements:
37
- - - ! '>='
150
+ - - '>='
38
151
  - !ruby/object:Gem::Version
39
152
  version: '0'
40
153
  requirements: []
41
154
  rubyforge_project:
42
- rubygems_version: 1.8.21
155
+ rubygems_version: 2.0.3
43
156
  signing_key:
44
- specification_version: 3
157
+ specification_version: 4
45
158
  summary: Open web browser to view remote Git repositories
46
- test_files: []
159
+ test_files:
160
+ - spec/bin_spec.rb
161
+ - spec/lib/git/browse/remote/core_spec.rb
47
162
  has_rdoc: