github 0.1.1 → 0.4.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.
Files changed (47) hide show
  1. data/History.txt +37 -0
  2. data/Manifest +33 -12
  3. data/README.md +187 -0
  4. data/Rakefile +44 -0
  5. data/bin/gh +8 -0
  6. data/bin/github +4 -1
  7. data/github.gemspec +29 -34
  8. data/lib/commands/commands.rb +249 -0
  9. data/lib/commands/helpers.rb +486 -0
  10. data/lib/commands/issues.rb +17 -0
  11. data/lib/commands/network.rb +110 -0
  12. data/lib/github.rb +117 -29
  13. data/lib/github/command.rb +69 -14
  14. data/lib/github/extensions.rb +39 -0
  15. data/lib/github/ui.rb +19 -0
  16. data/setup.rb +1551 -0
  17. data/spec/command_spec.rb +82 -0
  18. data/spec/commands/command_browse_spec.rb +36 -0
  19. data/spec/commands/command_clone_spec.rb +87 -0
  20. data/spec/commands/command_create-from-local_spec.rb +7 -0
  21. data/spec/commands/command_fetch_spec.rb +56 -0
  22. data/spec/commands/command_fork_spec.rb +44 -0
  23. data/spec/commands/command_helper.rb +170 -0
  24. data/spec/commands/command_home_spec.rb +20 -0
  25. data/spec/commands/command_info_spec.rb +23 -0
  26. data/spec/commands/command_issues_spec.rb +97 -0
  27. data/spec/commands/command_network_spec.rb +30 -0
  28. data/spec/commands/command_pull-request_spec.rb +51 -0
  29. data/spec/commands/command_pull_spec.rb +82 -0
  30. data/spec/commands/command_search_spec.rb +34 -0
  31. data/spec/commands/command_track_spec.rb +82 -0
  32. data/spec/commands_spec.rb +49 -0
  33. data/spec/extensions_spec.rb +36 -0
  34. data/spec/github_spec.rb +85 -0
  35. data/spec/helper_spec.rb +368 -0
  36. data/spec/spec_helper.rb +160 -4
  37. data/spec/windoze_spec.rb +38 -0
  38. metadata +114 -47
  39. data/README +0 -49
  40. data/commands/commands.rb +0 -54
  41. data/commands/helpers.rb +0 -79
  42. data/spec/helpers/owner_spec.rb +0 -12
  43. data/spec/helpers/project_spec.rb +0 -12
  44. data/spec/helpers/public_url_for_spec.rb +0 -12
  45. data/spec/helpers/repo_for_spec.rb +0 -12
  46. data/spec/helpers/user_and_repo_from_spec.rb +0 -15
  47. data/spec/helpers/user_for_spec.rb +0 -12
data/spec/command_spec.rb CHANGED
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe GitHub::Command do
4
+ before(:each) do
5
+ @command = GitHub::Command.new(proc { |x| puts x })
6
+ end
7
+
8
+ it "should return a GitHub::Helper" do
9
+ @command.helper.should be_instance_of(GitHub::Helper)
10
+ end
11
+
12
+ it "should call successfully" do
13
+ @command.should_receive(:puts).with("test").once
14
+ @command.call("test")
15
+ end
16
+
17
+ it "should return options" do
18
+ GitHub.should_receive(:options).with().once.and_return({:ssh => true})
19
+ @command.options.should == {:ssh => true}
20
+ end
21
+
22
+ it "should successfully call out to the shell" do
23
+ unguard(Kernel, :fork)
24
+ unguard(Kernel, :exec)
25
+ hi = @command.sh("echo hi")
26
+ hi.should == "hi"
27
+ hi.out.should == "hi"
28
+ hi.out?.should be(true)
29
+ hi.error.should be_nil
30
+ hi.error?.should be(false)
31
+ hi.command.should == "echo hi"
32
+ if RUBY_PLATFORM =~ /mingw|mswin/
33
+ command = "cmd /c echo bye >&2"
34
+ else
35
+ command = "echo bye >&2"
36
+ end
37
+ bye = @command.sh(command)
38
+ bye.should == "bye"
39
+ bye.out.should be_nil
40
+ bye.out?.should be(false)
41
+ bye.error.should == "bye"
42
+ bye.error?.should be(true)
43
+ bye.command.should == command
44
+ hi_and_bye = @command.sh("echo hi; echo bye >&2")
45
+ hi_and_bye.should == "hi"
46
+ hi_and_bye.out.should == "hi"
47
+ hi_and_bye.out?.should be(true)
48
+ hi_and_bye.error.should == "bye"
49
+ hi_and_bye.error?.should be(true)
50
+ hi_and_bye.command.should == "echo hi; echo bye >&2"
51
+ end
52
+
53
+ it "should return the results of a git operation" do
54
+ GitHub::Command::Shell.should_receive(:new).with("git rev-parse master").once.and_return do |*cmds|
55
+ s = mock("GitHub::Commands::Shell")
56
+ s.should_receive(:run).once.and_return("sha1")
57
+ s
58
+ end
59
+ @command.git("rev-parse master").should == "sha1"
60
+ end
61
+
62
+ it "should print the results of a git operation" do
63
+ @command.should_receive(:puts).with("sha1").once
64
+ GitHub::Command::Shell.should_receive(:new).with("git rev-parse master").once.and_return do |*cmds|
65
+ s = mock("GitHub::Commands::Shell")
66
+ s.should_receive(:run).once.and_return("sha1")
67
+ s
68
+ end
69
+ @command.pgit("rev-parse master")
70
+ end
71
+
72
+ it "should exec a git command" do
73
+ @command.should_receive(:exec).with("git rev-parse master").once
74
+ @command.git_exec "rev-parse master"
75
+ end
76
+
77
+ it "should die" do
78
+ @command.should_receive(:puts).once.with("=> message")
79
+ @command.should_receive(:exit!).once
80
+ @command.die "message"
81
+ end
82
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/command_helper'
3
+
4
+ describe "github browse" do
5
+ include CommandHelper
6
+
7
+ specify "browse should open the project home page with the current branch" do
8
+ running :browse do
9
+ setup_url_for
10
+ setup_user_and_branch("user", "test-branch")
11
+ @helper.should_receive(:open).once.with("https://github.com/user/project/tree/test-branch")
12
+ end
13
+ end
14
+
15
+ specify "browse pending should open the project home page with the 'pending' branch" do
16
+ running :browse, "pending" do
17
+ setup_url_for
18
+ setup_user_and_branch("user", "test-branch")
19
+ @helper.should_receive(:open).once.with("https://github.com/user/project/tree/pending")
20
+ end
21
+ end
22
+
23
+ specify "browse defunkt pending should open the home page of defunkt's fork with the 'pending' branch" do
24
+ running :browse, "defunkt", "pending" do
25
+ setup_url_for
26
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
27
+ end
28
+ end
29
+
30
+ specify "browse defunkt/pending should open the home page of defunkt's fork with the 'pending' branch" do
31
+ running :browse, "defunkt/pending" do
32
+ setup_url_for
33
+ @helper.should_receive(:open).once.with("https://github.com/defunkt/project/tree/pending")
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,87 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/command_helper'
3
+
4
+ describe "github clone" do
5
+ include CommandHelper
6
+
7
+ # -- clone --
8
+ specify "clone should die with no args" do
9
+ running :clone do
10
+ @command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died" }
11
+ self.should raise_error(RuntimeError)
12
+ end
13
+ end
14
+
15
+ specify "clone should fall through with just one arg" do
16
+ running :clone, "git://git.kernel.org/linux.git" do
17
+ @command.should_receive(:git_exec).with("clone git://git.kernel.org/linux.git")
18
+ end
19
+ end
20
+
21
+ specify "clone defunkt github-gem should clone the repo" do
22
+ running :clone, "defunkt", "github-gem" do
23
+ @command.should_receive(:current_user?).and_return(nil)
24
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
25
+ end
26
+ end
27
+
28
+ specify "clone defunkt/github-gem should clone the repo" do
29
+ running :clone, "defunkt/github-gem" do
30
+ @command.should_receive(:current_user?).and_return(nil)
31
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
32
+ end
33
+ end
34
+
35
+ specify "clone --ssh defunkt github-gem should clone the repo using the private URL" do
36
+ running :clone, "--ssh", "defunkt", "github-gem" do
37
+ @command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git")
38
+ end
39
+ end
40
+
41
+ specify "clone defunkt github-gem repo should clone the repo into the dir 'repo'" do
42
+ running :clone, "defunkt", "github-gem", "repo" do
43
+ @command.should_receive(:current_user?).and_return(nil)
44
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
45
+ end
46
+ end
47
+
48
+ specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
49
+ running :clone, "defunkt/github-gem", "repo" do
50
+ @command.should_receive(:current_user?).and_return(nil)
51
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
52
+ end
53
+ end
54
+
55
+ specify "clone --ssh defunkt github-gem repo should clone the repo using the private URL into the dir 'repo'" do
56
+ running :clone, "--ssh", "defunkt", "github-gem", "repo" do
57
+ @command.should_receive(:git_exec).with("clone git@github.com:defunkt/github-gem.git repo")
58
+ end
59
+ end
60
+
61
+ specify "clone defunkt/github-gem repo should clone the repo into the dir 'repo'" do
62
+ running :clone, "defunkt/github-gem", "repo" do
63
+ @command.should_receive(:current_user?).and_return(nil)
64
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git repo")
65
+ end
66
+ end
67
+
68
+ specify "clone a selected repo after showing search results" do
69
+ running :clone, "--search", "github-gem" do
70
+ json = StringIO.new '{"repositories":[' +
71
+ '{"name":"github-gem","size":300,"followers":499,"username":"defunkt","language":"Ruby","fork":false,"id":"repo-1653","type":"repo","pushed":"2008-12-04T03:14:00Z","forks":59,"description":"The official `github` command line helper for simplifying your GitHub experience.","score":3.4152448,"created":"2008-02-28T09:35:34Z"},' +
72
+ '{"name":"github-gem-builder","size":76,"followers":26,"username":"pjhyett","language":"Ruby","fork":false,"id":"repo-67489","type":"repo","pushed":"2008-11-04T04:54:57Z","forks":3,"description":"The scripts used to build RubyGems on GitHub","score":3.4152448,"created":"2008-10-24T22:29:32Z"}' +
73
+ ']}'
74
+ json.rewind
75
+ question_list = <<-LIST.gsub(/^ /, '').split("\n").compact
76
+ defunkt/github-gem # The official `github` command line helper for simplifying your GitHub experience.
77
+ pjhyett/github-gem-builder # The scripts used to build RubyGems on GitHub
78
+ LIST
79
+ @command.should_receive(:open).with("http://github.com/api/v1/json/search/github-gem").and_return(json)
80
+ GitHub::UI.should_receive(:display_select_list).with(question_list).
81
+ and_return("defunkt/github-gem")
82
+ @command.should_receive(:current_user?).and_return(nil)
83
+ @command.should_receive(:git_exec).with("clone git://github.com/defunkt/github-gem.git")
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/command_helper'
3
+
4
+ describe "github create-from-local" do
5
+ include CommandHelper
6
+
7
+ end
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/command_helper'
3
+
4
+ describe "github fetch" do
5
+ include CommandHelper
6
+
7
+ specify "fetch should die with no args" do
8
+ running :fetch do
9
+ @command.should_receive(:die).with("Specify a user to pull from").and_return { raise "Died" }
10
+ self.should raise_error(RuntimeError)
11
+ end
12
+ end
13
+
14
+ specify "fetch defunkt should start tracking defunkt if they're not already tracked" do
15
+ running :fetch, "defunkt" do
16
+ setup_remote(:origin, :user => "user", :ssh => true)
17
+ setup_remote(:external, :url => "home:/path/to/project.git")
18
+ GitHub.should_receive(:invoke).with(:track, "defunkt").and_return { raise "Tracked" }
19
+ self.should raise_error("Tracked")
20
+ end
21
+ end
22
+
23
+ specify "fetch defunkt should create defunkt/master and fetch from the defunkt remote" do
24
+ running :fetch, "defunkt" do
25
+ setup_remote(:defunkt)
26
+ @helper.should_receive(:branch_dirty?).and_return false
27
+ @command.should_receive(:git).with("fetch defunkt master:refs/remotes/defunkt/master").ordered
28
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/master refs/remotes/defunkt/master").ordered
29
+ @command.should_receive(:git_exec).with("checkout defunkt/master").ordered
30
+ stdout.should == "Fetching defunkt/master\n"
31
+ end
32
+ end
33
+
34
+ specify "fetch defunkt/wip should create defunkt/wip and fetch from wip branch on defunkt remote" do
35
+ running :fetch, "defunkt/wip" do
36
+ setup_remote(:defunkt, :remote_branches => ["master", "wip"])
37
+ @helper.should_receive(:branch_dirty?).and_return false
38
+ @command.should_receive(:git).with("fetch defunkt wip:refs/remotes/defunkt/wip").ordered
39
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/wip refs/remotes/defunkt/wip").ordered
40
+ @command.should_receive(:git_exec).with("checkout defunkt/wip").ordered
41
+ stdout.should == "Fetching defunkt/wip\n"
42
+ end
43
+ end
44
+
45
+ specify "fetch --merge defunkt should fetch from defunkt remote into current branch" do
46
+ running :fetch, "--merge", "defunkt" do
47
+ setup_remote(:defunkt)
48
+ @helper.should_receive(:branch_dirty?).and_return false
49
+ @command.should_receive(:git).with("fetch defunkt master:refs/remotes/defunkt/master").ordered
50
+ @command.should_receive(:git).with("update-ref refs/heads/defunkt/master refs/remotes/defunkt/master").ordered
51
+ @command.should_receive(:git_exec).with("checkout defunkt/master").ordered
52
+ stdout.should == "Fetching defunkt/master\n"
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require File.dirname(__FILE__) + '/command_helper'
3
+
4
+ describe "github fork" do
5
+ include CommandHelper
6
+
7
+ specify "fork should print out help" do
8
+ running :fork do
9
+ @helper.should_receive(:remotes).and_return({})
10
+ @command.should_receive(:die).with("Specify a user/project to fork, or run from within a repo").and_return { raise "Died" }
11
+ self.should raise_error(RuntimeError)
12
+ end
13
+ end
14
+
15
+ specify "fork this repo should create github fork and replace origin remote" do
16
+ running :fork do
17
+ setup_github_token
18
+ setup_url_for "origin", "defunkt", "github-gem"
19
+ setup_remote "origin", :user => "defunkt", :project => "github-gem"
20
+ setup_user_and_branch
21
+ @command.should_receive(:sh).with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
22
+ @command.should_receive(:git, "config remote.origin.url git@github.com/drnic/github-gem.git")
23
+ stdout.should == "defunkt/github-gem forked\n"
24
+ end
25
+ end
26
+
27
+ specify "fork a user/project repo" do
28
+ running :fork, "defunkt/github-gem" do
29
+ setup_github_token
30
+ @command.should_receive(:sh).with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
31
+ @command.should_receive(:git_exec, "clone git://github.com/defunkt/github-gem.git")
32
+ stdout.should == "Giving GitHub a moment to create the fork...\n"
33
+ end
34
+ end
35
+
36
+ specify "fork a user project repo" do
37
+ running :fork, "defunkt", "github-gem" do
38
+ setup_github_token
39
+ @command.should_receive("sh").with("curl -F 'login=drnic' -F 'token=MY_GITHUB_TOKEN' http://github.com/defunkt/github-gem/fork")
40
+ @command.should_receive(:git_exec, "clone git://github.com/defunkt/github-gem.git")
41
+ stdout.should == "Giving GitHub a moment to create the fork...\n"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,170 @@
1
+ module CommandHelper
2
+ def running(cmd, *args, &block)
3
+ Runner.new(self, cmd, *args, &block).run
4
+ end
5
+
6
+ class Runner
7
+ include SetupMethods
8
+
9
+ def initialize(parent, cmd, *args, &block)
10
+ @cmd_name = cmd.to_s
11
+ @command = GitHub.find_command(cmd)
12
+ @helper = @command.helper
13
+ @args = args
14
+ @block = block
15
+ @parent = parent
16
+ end
17
+
18
+ def run
19
+ self.instance_eval &@block
20
+ mock_remotes unless @remotes.nil?
21
+ GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/commands.rb")
22
+ GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/helpers.rb")
23
+ GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/network.rb")
24
+ GitHub.should_receive(:load).with(GitHub::BasePath + "/commands/issues.rb")
25
+ args = @args.clone
26
+ GitHub.parse_options(args) # strip out the flags
27
+ GitHub.should_receive(:invoke).with(@cmd_name, *args).and_return do
28
+ GitHub.send(GitHub.send(:__mock_proxy).send(:munge, :invoke), @cmd_name, *args)
29
+ end
30
+ invoke = lambda { GitHub.activate([@cmd_name, *@args]) }
31
+ if @expected_result
32
+ expectation, result = @expected_result
33
+ case result
34
+ when Spec::Matchers::RaiseError, Spec::Matchers::Change, Spec::Matchers::ThrowSymbol
35
+ invoke.send expectation, result
36
+ else
37
+ invoke.call.send expectation, result
38
+ end
39
+ else
40
+ invoke.call
41
+ end
42
+ @stdout_mock.invoke unless @stdout_mock.nil?
43
+ @stderr_mock.invoke unless @stderr_mock.nil?
44
+ end
45
+
46
+ def setup_remote(remote, options = {:user => nil, :project => "project", :remote_branches => nil})
47
+ @remotes ||= {}
48
+ @remote_branches ||= {}
49
+ user = options[:user] || remote
50
+ project = options[:project]
51
+ ssh = options[:ssh]
52
+ url = options[:url]
53
+ remote_branches = options[:remote_branches] || ["master"]
54
+ if url
55
+ @remotes[remote] = url
56
+ elsif ssh
57
+ @remotes[remote] = "git@github.com:#{user}/#{project}.git"
58
+ else
59
+ @remotes[remote] = "git://github.com/#{user}/#{project}.git"
60
+ end
61
+
62
+ @remote_branches[remote] = (@remote_branches[remote] || Array.new) | remote_branches
63
+ @helper.should_receive(:remote_branch?).any_number_of_times.and_return do |remote, branch|
64
+ @remote_branches.fetch(remote.to_sym,[]).include?(branch)
65
+ end
66
+ end
67
+
68
+ def mock_remotes()
69
+ @helper.should_receive(:remotes).any_number_of_times.and_return(@remotes)
70
+ end
71
+
72
+ def mock_members(members)
73
+ @helper.should_receive(:network_members).any_number_of_times.and_return(members)
74
+ end
75
+
76
+ def should(result)
77
+ @expected_result = [:should, result]
78
+ end
79
+
80
+ def should_not(result)
81
+ @expected_result = [:should_not, result]
82
+ end
83
+
84
+ def stdout
85
+ if @stdout_mock.nil?
86
+ output = ""
87
+ @stdout_mock = DeferredMock.new(output)
88
+ $stdout.should_receive(:write).any_number_of_times do |str|
89
+ output << str
90
+ end
91
+ end
92
+ @stdout_mock
93
+ end
94
+
95
+ def stderr
96
+ if @stderr_mock.nil?
97
+ output = ""
98
+ @stderr_mock = DeferredMock.new(output)
99
+ $stderr.should_receive(:write).any_number_of_times do |str|
100
+ output << str
101
+ end
102
+ end
103
+ @stderr_mock
104
+ end
105
+
106
+ class DeferredMock
107
+ def initialize(obj = nil)
108
+ @obj = obj
109
+ @calls = []
110
+ @expectations = []
111
+ end
112
+
113
+ attr_reader :obj
114
+
115
+ def invoke(obj = nil)
116
+ obj ||= @obj
117
+ @calls.each do |sym, args|
118
+ obj.send sym, *args
119
+ end
120
+ @expectations.each do |exp|
121
+ exp.invoke
122
+ end
123
+ end
124
+
125
+ def should(*args)
126
+ if args.empty?
127
+ exp = Expectation.new(self, :should)
128
+ @expectations << exp
129
+ exp
130
+ else
131
+ @calls << [:should, args]
132
+ end
133
+ end
134
+
135
+ def should_not(*args)
136
+ if args.empty?
137
+ exp = Expectation.new(self, :should_not)
138
+ @expectations << exp
139
+ exp
140
+ else
141
+ @calls << [:should_not, args]
142
+ end
143
+ end
144
+
145
+ class Expectation
146
+ def initialize(mock, call)
147
+ @mock = mock
148
+ @call = call
149
+ @calls = []
150
+ end
151
+
152
+ undef_method *(instance_methods.map { |x| x.to_sym } - [:__id__, :__send__])
153
+
154
+ def invoke
155
+ @calls.each do |sym, args|
156
+ (@mock.obj.send @call).send sym, *args
157
+ end
158
+ end
159
+
160
+ def method_missing(sym, *args)
161
+ @calls << [sym, args]
162
+ end
163
+ end
164
+ end
165
+
166
+ def method_missing(sym, *args)
167
+ @parent.send sym, *args
168
+ end
169
+ end
170
+ end