gemcutter 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -23,27 +23,21 @@ No. In fact it will make their lives better: it will be easier to get to project
23
23
  GitHub's gem system is great, but it's not the canonical source by default. The nice part is that it takes the approval process out, but the namespacing on gems makes it hard for those new to the community to determine what is the right copy to use. Also, the goals here are much different and the site as a whole can be improved over time by the community.
24
24
 
25
25
  *How can I gain access of my gem that was available through RubyForge?*<br />
26
- The plan currently is to provide a key to upload to your RubyForge account, and then Gemcutter will mark you as the owner based on that.
26
+ The full process is coming soon!
27
27
 
28
28
  *How can I help?*<br />
29
29
  Fork away, and read the next section! Feel free to bug qrush via a message or on FreeNode if you're interested.
30
30
 
31
- h2. Next up
31
+ h2. Contributions
32
32
 
33
- What's finished so far:
33
+ Gemcutter has a 'commit-bit' policy, much like the Rubinius project. Submit a patch that is accepted, and you'll get full commit access to the project. Please check the wiki for more information.
34
34
 
35
- * Simple site (list, push, update)
36
- * Releasing/updating gems via @gem push@
37
- * Project pages
38
- * Authentication/accounts
39
- * Gem server up and running
35
+ If you're looking for things to hack on, please check GitHub Issues. If you've found bugs or have feature ideas don't be afraid to pipe up and ask the mailing list about them.
40
36
 
41
- What's coming:
37
+ h2. Testing
42
38
 
43
- * RubyForge migration for gem projects
44
- * Fully fledged API documentation
45
- * Search via the API and site
39
+ Make sure you run @rake gemcutter:index:create@ before running the test suite, otherwise it might complain. Better solutions to this are more than welcome.
46
40
 
47
- h2. Testing
41
+ h2. License
48
42
 
49
- Make sure you run `rake gemcutter:index:create` before running the test suite, otherwise it might complain. Better solutions to this are more than welcome.
43
+ Gemcutter uses the MIT license. Please check the LICENSE file for more details.
@@ -0,0 +1,66 @@
1
+ class Gem::AbstractCommand < Gem::Command
2
+ def api_key
3
+ Gem.configuration[:gemcutter_key]
4
+ end
5
+
6
+ def gemcutter_url
7
+ if ENV['test']
8
+ "http://gemcutter.local"
9
+ else
10
+ "https://gemcutter.heroku.com"
11
+ end
12
+ end
13
+
14
+ def setup
15
+ use_proxy! if http_proxy
16
+ sign_in unless api_key
17
+ end
18
+
19
+ def sign_in
20
+ say "Enter your Gemcutter credentials. Don't have an account yet? Create one at #{URL}/sign_up"
21
+
22
+ email = ask("Email: ")
23
+ password = ask_for_password("Password: ")
24
+
25
+ url = URI.parse("#{gemcutter_url}/api_key")
26
+
27
+ http = Net::HTTP.new(url.host, url.port)
28
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
29
+ http.use_ssl = (url.scheme == 'https')
30
+ request = Net::HTTP::Get.new(url.path)
31
+ request.basic_auth email, password
32
+ response = http.request(request)
33
+
34
+ case response
35
+ when Net::HTTPSuccess
36
+ Gem.configuration[:gemcutter_key] = response.body
37
+ Gem.configuration.write
38
+ say "Signed in. Your api key has been stored in ~/.gemrc"
39
+ else
40
+ say response.body
41
+ terminate_interaction
42
+ end
43
+ end
44
+
45
+ def use_proxy!
46
+ proxy_uri = http_proxy
47
+ @proxy_class = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
48
+ end
49
+
50
+ def proxy_class
51
+ @proxy_class || Net::HTTP
52
+ end
53
+
54
+ # @return [URI, nil] the HTTP-proxy as a URI if set; +nil+ otherwise
55
+ def http_proxy
56
+ proxy = Gem.configuration[:http_proxy]
57
+ return nil if proxy.nil? || proxy == :no_proxy
58
+ URI.parse(proxy)
59
+ end
60
+
61
+ def ask_for_password(message)
62
+ password = ui.ask_for_password(message)
63
+ ui.say("\n")
64
+ password
65
+ end
66
+ end
@@ -0,0 +1,99 @@
1
+ require 'open-uri'
2
+ require 'net/scp'
3
+ require 'json'
4
+ require 'tempfile'
5
+
6
+ class Gem::Commands::MigrateCommand < Gem::AbstractCommand
7
+ attr_reader :rubygem
8
+
9
+ def description
10
+ 'Migrate a gem your own from Rubyforge to Gemcutter.'
11
+ end
12
+
13
+ def initialize
14
+ super 'migrate', description
15
+ end
16
+
17
+ def execute
18
+ setup
19
+ migrate
20
+ end
21
+
22
+ def migrate
23
+ find(get_one_gem_name)
24
+ token = get_token
25
+ upload_token(token)
26
+ check_for_approved
27
+ end
28
+
29
+ def find(name)
30
+ begin
31
+ data = open("#{gemcutter_url}/gems/#{name}.json")
32
+ @rubygem = JSON.parse(data.string)
33
+ rescue OpenURI::HTTPError
34
+ say "This gem is currently not hosted on Gemcutter."
35
+ terminate_interaction
36
+ rescue JSON::ParserError => json_error
37
+ say "There was a problem parsing the data: #{json_error}"
38
+ terminate_interaction
39
+ end
40
+ end
41
+
42
+ def get_token
43
+ say "Starting migration of #{rubygem["name"]} from RubyForge..."
44
+
45
+ url = URI.parse("#{gemcutter_url}/gems/#{rubygem["slug"]}/migrate")
46
+
47
+ http = proxy_class.new(url.host, url.port)
48
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
49
+ http.use_ssl = (url.scheme == 'https')
50
+ request = proxy_class::Post.new(url.path)
51
+ request.add_field("Content-Length", 0)
52
+ request.add_field("Authorization", api_key)
53
+ response = http.request(request)
54
+
55
+ case response
56
+ when Net::HTTPSuccess
57
+ say "A migration token has been created."
58
+ response.body
59
+ else
60
+ say response.body
61
+ terminate_interaction
62
+ end
63
+ end
64
+
65
+ def upload_token(token)
66
+ url = "#{self.rubygem['rubyforge_project']}.rubyforge.org"
67
+ say "Uploading the migration token to #{url}. Please enter your RubyForge login:"
68
+ login = ask("Login: ")
69
+ password = ask_for_password("Password: ")
70
+
71
+ begin
72
+ Net::SCP.start(url, login, :password => password) do |scp|
73
+ temp_token = Tempfile.new("token")
74
+ temp_token.chmod 0644
75
+ temp_token.write(token)
76
+ temp_token.close
77
+ scp.upload! temp_token.path, "/var/www/gforge-projects/#{rubygem['rubyforge_project']}/migrate-#{rubygem['name']}.html"
78
+ end
79
+ say "Successfully uploaded your token."
80
+ rescue Exception => e
81
+ say "There was a problem uploading your token: #{e}"
82
+ end
83
+ end
84
+
85
+ def check_for_approved
86
+ say "Asking Gemcutter to verify the upload..."
87
+ url = URI.parse("#{gemcutter_url}/gems/#{rubygem["slug"]}/migrate")
88
+
89
+ http = proxy_class.new(url.host, url.port)
90
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
91
+ http.use_ssl = (url.scheme == 'https')
92
+ request = proxy_class::Put.new(url.path)
93
+ request.add_field("Content-Length", 0)
94
+ request.add_field("Authorization", api_key)
95
+ response = http.request(request)
96
+
97
+ say response.body
98
+ end
99
+ end
data/lib/commands/push.rb CHANGED
@@ -1,7 +1,11 @@
1
1
  require 'net/http'
2
2
  require 'net/https'
3
+ require 'rubygems/local_remote_options'
4
+
5
+ class Gem::Commands::PushCommand < Gem::AbstractCommand
6
+
7
+ include Gem::LocalRemoteOptions
3
8
 
4
- class Gem::Commands::PushCommand < Gem::Command
5
9
  def description
6
10
  'Push a gem up to Gemcutter'
7
11
  end
@@ -11,46 +15,29 @@ class Gem::Commands::PushCommand < Gem::Command
11
15
  end
12
16
 
13
17
  def usage
14
- "#{programe_name} GEM"
18
+ "#{program_name} GEM"
15
19
  end
16
20
 
17
21
  def initialize
18
22
  super 'push', description
23
+ add_proxy_option
19
24
  end
20
25
 
21
26
  def execute
22
- sign_in unless api_key
27
+ setup
23
28
  send_gem
24
29
  end
25
30
 
26
- def ask_for_password(message)
27
- password = ui.ask_for_password(message)
28
- ui.say("\n")
29
- password
30
- end
31
-
32
- def api_key
33
- Gem.configuration[:gemcutter_key]
34
- end
35
-
36
- def push_url
37
- if ENV['test']
38
- "http://gemcutter.local"
39
- else
40
- "https://gemcutter.heroku.com"
41
- end
42
- end
43
-
44
31
  def send_gem
45
32
  say "Pushing gem to Gemcutter..."
46
33
 
47
34
  name = get_one_gem_name
48
- url = URI.parse("#{push_url}/gems")
35
+ url = URI.parse("#{gemcutter_url}/gems")
49
36
 
50
- http = Net::HTTP.new(url.host, url.port)
37
+ http = proxy_class.new(url.host, url.port)
51
38
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
52
39
  http.use_ssl = (url.scheme == 'https')
53
- request = Net::HTTP::Post.new(url.path)
40
+ request = proxy_class::Post.new(url.path)
54
41
  request.body = File.open(name).read
55
42
  request.add_field("Content-Length", request.body.size)
56
43
  request.add_field("Authorization", api_key)
@@ -60,38 +47,4 @@ class Gem::Commands::PushCommand < Gem::Command
60
47
  say response.body
61
48
  end
62
49
 
63
- def sign_in
64
- say "Enter your Gemcutter credentials. Don't have an account yet? Create one at #{URL}/sign_up"
65
-
66
- email = ask("Email: ")
67
- password = ask_for_password("Password: ")
68
-
69
- url = URI.parse("#{push_url}/api_key")
70
-
71
- http = Net::HTTP.new(url.host, url.port)
72
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
73
- http.use_ssl = (url.scheme == 'https')
74
- request = Net::HTTP::Get.new(url.path)
75
- request.basic_auth email, password
76
- response = http.request(request)
77
-
78
- case response
79
- when Net::HTTPSuccess
80
- Gem.configuration[:gemcutter_key] = response.body
81
- Gem.configuration.write
82
- say "Signed in. Your api key has been stored in ~/.gemrc"
83
- else
84
- say response.body
85
- terminate_interaction
86
- end
87
- end
88
- end
89
-
90
- class Gem::StreamUI
91
- def ask_for_password(message)
92
- system "stty -echo"
93
- password = ask(message)
94
- system "stty echo"
95
- password
96
- end
97
50
  end
@@ -1,4 +1,4 @@
1
- class Gem::Commands::TumbleCommand < Gem::Command
1
+ class Gem::Commands::TumbleCommand < Gem::AbstractCommand
2
2
  def description
3
3
  'Enable or disable Gemcutter as your primary gem source.'
4
4
  end
@@ -24,9 +24,9 @@ class Gem::Commands::TumbleCommand < Gem::Command
24
24
  end
25
25
 
26
26
  def show_sources
27
- puts "Your gem sources are now:"
27
+ say "Your gem sources are now:"
28
28
  Gem.sources.each do |source|
29
- puts "- #{source}"
29
+ say "- #{source}"
30
30
  end
31
31
  end
32
32
  end
@@ -1,11 +1,20 @@
1
1
  $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
2
 
3
3
  require 'rubygems/command_manager'
4
+ require 'commands/abstract_command'
4
5
 
5
- require 'commands/push'
6
- require 'commands/tumble'
7
-
8
- Gem::CommandManager.instance.register_command :push
9
- Gem::CommandManager.instance.register_command :tumble
6
+ %w[migrate push tumble].each do |command|
7
+ require "commands/#{command}"
8
+ Gem::CommandManager.instance.register_command command.to_sym
9
+ end
10
10
 
11
11
  URL = "http://gemcutter.org" unless defined?(URL)
12
+
13
+ class Gem::StreamUI
14
+ def ask_for_password(message)
15
+ system "stty -echo"
16
+ password = ask(message)
17
+ system "stty echo"
18
+ password
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'redgreen'
5
+ require 'active_support'
6
+ require 'active_support/test_case'
7
+ gem 'fakeweb', '>= 1.2.5'
8
+ require 'fakeweb'
9
+ require 'rr'
10
+
11
+ FakeWeb.allow_net_connect = false
12
+
13
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
14
+
15
+ require "rubygems_plugin"
16
+
17
+ class CommandTest < ActiveSupport::TestCase
18
+ include RR::Adapters::TestUnit unless include?(RR::Adapters::TestUnit)
19
+ end
@@ -0,0 +1,113 @@
1
+ require File.dirname(__FILE__) + '/../../command_helper'
2
+
3
+ class Gem::Commands::FakeCommand < Gem::AbstractCommand
4
+ def description
5
+ 'fake command'
6
+ end
7
+
8
+ def initialize
9
+ super 'fake', description
10
+ end
11
+
12
+ def execute
13
+ end
14
+ end
15
+
16
+ class AbstractCommandTest < CommandTest
17
+ context "with an fake command" do
18
+ setup do
19
+ @command = Gem::Commands::FakeCommand.new
20
+ stub(@command).say
21
+ end
22
+
23
+ context "parsing the proxy" do
24
+ should "return nil if no proxy is set" do
25
+ stub(Gem).configuration { { :http_proxy => nil } }
26
+ assert_equal nil, @command.http_proxy
27
+ end
28
+
29
+ should "return nil if the proxy is set to :no_proxy" do
30
+ stub(Gem).configuration { { :http_proxy => :no_proxy } }
31
+ assert_equal nil, @command.http_proxy
32
+ end
33
+
34
+ should "return a proxy as a URI if set" do
35
+ stub(Gem).configuration { { :http_proxy => 'http://proxy.example.org:9192' } }
36
+ assert_equal 'proxy.example.org', @command.http_proxy.host
37
+ assert_equal 9192, @command.http_proxy.port
38
+ end
39
+ end
40
+
41
+ # TODO: rewrite all of this junk using spies
42
+ #should "use a proxy if specified" do
43
+ # stub(@command).http_proxy { 'http://some.proxy' }
44
+ # mock(@command).use_proxy!
45
+ # mock(@command).sign_in
46
+ # @command.setup
47
+ #end
48
+
49
+ #should "not use a proxy if unspecified" do
50
+ # stub(@command).http_proxy { nil }
51
+ # mock(@command).use_proxy!.never
52
+ # mock(@command).sign_in
53
+ # @command.setup
54
+ #end
55
+
56
+ should "sign in if no api key" do
57
+ stub(Gem).configuration { {:gemcutter_key => nil} }
58
+ mock(@command).sign_in
59
+ @command.setup
60
+ end
61
+
62
+ should "not sign in if api key exists" do
63
+ stub(Gem).configuration { {:gemcutter_key => "1234567890"} }
64
+ mock(@command).sign_in.never
65
+ @command.setup
66
+ end
67
+
68
+ context "using the proxy" do
69
+ setup do
70
+ stub(Gem).configuration { { :http_proxy => "http://gilbert:sekret@proxy.example.org:8081" } }
71
+ @proxy_class = Object.new
72
+ mock(Net::HTTP).Proxy('proxy.example.org', 8081, 'gilbert', 'sekret') { @proxy_class }
73
+ @command.use_proxy!
74
+ end
75
+
76
+ should "replace Net::HTTP with a proxy version" do
77
+ assert_equal @proxy_class, @command.proxy_class
78
+ end
79
+ end
80
+
81
+ context "signing in" do
82
+ setup do
83
+ @email = "email"
84
+ @password = "password"
85
+ @key = "key"
86
+ mock(@command).say("Enter your Gemcutter credentials. Don't have an account yet? Create one at #{URL}/sign_up")
87
+ mock(@command).ask("Email: ") { @email }
88
+ mock(@command).ask_for_password("Password: ") { @password }
89
+ FakeWeb.register_uri :get, "https://#{@email}:#{@password}@gemcutter.heroku.com/api_key", :body => @key
90
+
91
+ @config = Object.new
92
+ stub(Gem).configuration { @config }
93
+ stub(@config)[:gemcutter_key] = @key
94
+ stub(@config).write
95
+ end
96
+
97
+ should "sign in" do
98
+ mock(@command).say("Signed in. Your api key has been stored in ~/.gemrc")
99
+ @command.sign_in
100
+ end
101
+
102
+ should "let the user know if there was a problem" do
103
+ @problem = "Access Denied"
104
+ mock(@command).say(@problem)
105
+ mock(@command).terminate_interaction
106
+ mock(@config).write.never
107
+
108
+ FakeWeb.register_uri :get, "https://#{@email}:#{@password}@gemcutter.heroku.com/api_key", :body => @problem, :status => 401
109
+ @command.sign_in
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '/../../command_helper'
2
+
3
+ class MigrateCommandTest < CommandTest
4
+ context "executing the command" do
5
+ setup do
6
+ @command = Gem::Commands::MigrateCommand.new
7
+ stub(@command).setup
8
+ stub(@command).migrate
9
+ end
10
+
11
+ should "setup and send the gem" do
12
+ @command.execute
13
+ assert_received(@command) { |subject| subject.setup }
14
+ assert_received(@command) { |subject| subject.migrate }
15
+ end
16
+ end
17
+
18
+ context "migrating" do
19
+ setup do
20
+ @command = Gem::Commands::MigrateCommand.new
21
+ @token = "deadbeef"
22
+ stub(@command).say
23
+ stub(@command).find
24
+ stub(@command).get_token { @token }
25
+ stub(@command).upload_token
26
+ stub(@command).check_for_approved
27
+ end
28
+
29
+ should "raise an error with no arguments" do
30
+ assert_raise Gem::CommandLineError do
31
+ @command.migrate
32
+ end
33
+ end
34
+
35
+ should "migrate the gem" do
36
+ stub(@command).get_one_gem_name { "mygem" }
37
+ @command.migrate
38
+ assert_received(@command) { |subject| subject.find("mygem") }
39
+ assert_received(@command) { |subject| subject.get_token }
40
+ assert_received(@command) { |subject| subject.upload_token(@token) }
41
+ assert_received(@command) { |subject| subject.check_for_approved }
42
+ end
43
+ end
44
+
45
+ context "ask about the gem" do
46
+ setup do
47
+ @command = Gem::Commands::MigrateCommand.new
48
+ stub(@command).say
49
+ stub(@command).terminate_interaction
50
+
51
+ @name = "rails"
52
+ @json = "{\"downloads\":4,\"name\":\"rails\",\"slug\":\"rails\",\"authors\":\"David Heinemeier Hansson\",\"version\":\"2.3.3\",\"rubyforge_project\":\"rails\",\"info\":\"Rails is a framework for building web-application using CGI, FCGI, mod_ruby, or WEBrick on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.\"}"
53
+ end
54
+
55
+ should "find gem info if it exists" do
56
+ FakeWeb.register_uri :get, "https://gemcutter.heroku.com/gems/#{@name}.json", :body => @json
57
+ @command.find(@name)
58
+ assert_equal JSON.parse(@json), @command.rubygem
59
+ end
60
+
61
+ should "dump out if the gem couldn't be found" do
62
+ FakeWeb.register_uri :get, "https://gemcutter.heroku.com/gems/#{@name}.json", :body => "Not hosted here.", :status => 404
63
+ @command.find(@name)
64
+ assert_received(@command) { |subject| subject.say(anything) }
65
+ assert_received(@command) { |subject| subject.terminate_interaction }
66
+ end
67
+
68
+ should "dump out if bad json is returned" do
69
+ FakeWeb.register_uri :get, "https://gemcutter.heroku.com/gems/#{@name}.json", :body => "bad data is bad"
70
+ @command.find(@name)
71
+ assert_received(@command) { |subject| subject.say(anything) }
72
+ assert_received(@command) { |subject| subject.terminate_interaction }
73
+ end
74
+ end
75
+
76
+ context "getting the token" do
77
+ setup do
78
+ @command = Gem::Commands::MigrateCommand.new
79
+ @name = "SomeGem"
80
+ @name = "somegem"
81
+ stub(@command).say
82
+ stub(@command).terminate_interaction
83
+ stub(@command).rubygem { { "name" => @name, "slug" => @slug } }
84
+ end
85
+
86
+ should "ask gemcutter to start the migration" do
87
+ token = "SECRET TOKEN"
88
+ FakeWeb.register_uri :post, "https://gemcutter.heroku.com/gems/#{@slug}/migrate", :body => token
89
+ assert_equal token, @command.get_token
90
+ end
91
+
92
+ should "dump out if gem could not be found" do
93
+ FakeWeb.register_uri :post, "https://gemcutter.heroku.com/gems/#{@slug}/migrate", :status => 404, :body => "not found"
94
+ @command.get_token
95
+ assert_received(@command) { |subject| subject.say("not found") }
96
+ assert_received(@command) { |subject| subject.terminate_interaction }
97
+ end
98
+
99
+ should "dump out if migration has already been completed" do
100
+ FakeWeb.register_uri :post, "https://gemcutter.heroku.com/gems/#{@slug}/migrate", :status => 403, :body => "already migrated"
101
+ @command.get_token
102
+ assert_received(@command) { |subject| subject.say("already migrated") }
103
+ assert_received(@command) { |subject| subject.terminate_interaction }
104
+ end
105
+ end
106
+
107
+ context "uploading the token" do
108
+ setup do
109
+ @command = Gem::Commands::MigrateCommand.new
110
+ @token = "deadbeef"
111
+ stub(@command).say
112
+ stub(@command).rubygem { { "rubyforge_project" => "bostonrb" } }
113
+ stub(Net::SCP).start
114
+ end
115
+
116
+ should "connect to rubyforge and upload away" do
117
+ stub(@command).ask { "user" }
118
+ stub(@command).ask_for_password { "secret" }
119
+ @command.upload_token(@token)
120
+
121
+ # TODO: figure out how to test the upload! in the block
122
+ assert_received(Net::SCP) { |subject| subject.start("bostonrb.rubyforge.org", "user", :password => "secret") }
123
+ end
124
+ end
125
+
126
+ context "checking if the rubygem was approved" do
127
+ setup do
128
+ @command = Gem::Commands::MigrateCommand.new
129
+ @slug = "rails"
130
+
131
+ stub(@command).say
132
+ stub(@command).rubygem { { "slug" => @slug } }
133
+ end
134
+
135
+ should "let the server decide the status" do
136
+ FakeWeb.register_uri :put, "https://gemcutter.heroku.com/gems/#{@slug}/migrate", :body => "Success!", :status => 400
137
+ @command.check_for_approved
138
+ assert_received(@command) { |subject| subject.say("Success!") }
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../../command_helper'
2
+
3
+ class PushCommandTest < CommandTest
4
+ context "pushing" do
5
+ setup do
6
+ @command = Gem::Commands::PushCommand.new
7
+ stub(@command).say
8
+ end
9
+
10
+ should "setup and send the gem" do
11
+ mock(@command).setup
12
+ mock(@command).send_gem
13
+ @command.execute
14
+ end
15
+
16
+ should "raise an error with no arguments" do
17
+ assert_raise Gem::CommandLineError do
18
+ @command.send_gem
19
+ end
20
+ end
21
+
22
+ should "push a gem" do
23
+ mock(@command).say("Pushing gem to Gemcutter...")
24
+ @response = "success"
25
+ FakeWeb.register_uri :post, "https://gemcutter.heroku.com/gems", :body => @response
26
+
27
+ @gem = "test"
28
+ @io = "io"
29
+ @config = { :gemcutter_key => "key" }
30
+
31
+ stub(File).open(@gem) { @io }
32
+ stub(@io).read.stub!.size
33
+
34
+ stub(@command).options { {:args => [@gem]} }
35
+ stub(Gem).configuration { @config }
36
+
37
+ mock(@command).say(@response)
38
+ @command.send_gem
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/../../command_helper'
2
+
3
+ class TumbleCommandTest < CommandTest
4
+ context "with a tumbler and some sources" do
5
+ setup do
6
+ @sources = ["gems.rubyforge.org", URL]
7
+ stub(Gem).sources { @sources }
8
+ @command = Gem::Commands::TumbleCommand.new
9
+ end
10
+
11
+ should "show sources" do
12
+ mock(@command).puts("Your gem sources are now:")
13
+ mock(@command).puts("- #{@sources.first}")
14
+ mock(@command).puts("- #{URL}")
15
+ @command.show_sources
16
+ end
17
+ end
18
+
19
+ context "tumbling the gem sources" do
20
+ setup do
21
+ @sources = ["http://rubyforge.org"]
22
+ stub(Gem).sources { @sources }
23
+ @config = Object.new
24
+ stub(Gem).configuration { @config }
25
+
26
+ @command = Gem::Commands::TumbleCommand.new
27
+ end
28
+
29
+ should "add gemcutter as first source" do
30
+ mock(@sources).unshift(URL)
31
+ mock(@config).write
32
+
33
+ @command.tumble
34
+ end
35
+
36
+ should "remove gemcutter if it's in the sources" do
37
+ mock(@sources).include?(URL) { true }
38
+ mock(@config).write
39
+ mock(@sources).delete(URL)
40
+
41
+ @command.tumble
42
+ end
43
+ end
44
+
45
+ context "executing the tumbler" do
46
+ setup do
47
+ @command = Gem::Commands::TumbleCommand.new
48
+ end
49
+
50
+ should "say thanks, tumble and show the sources" do
51
+ mock(@command).say(anything)
52
+ mock(@command).tumble
53
+ mock(@command).show_sources
54
+
55
+ @command.execute
56
+ end
57
+ end
58
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemcutter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Quaranto
@@ -9,10 +9,19 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-28 00:00:00 -04:00
12
+ date: 2009-08-10 00:00:00 -04:00
13
13
  default_executable:
14
- dependencies: []
15
-
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
16
25
  description:
17
26
  email: nick@quaran.to
18
27
  executables: []
@@ -22,6 +31,8 @@ extensions: []
22
31
  extra_rdoc_files:
23
32
  - README.textile
24
33
  files:
34
+ - lib/commands/abstract_command.rb
35
+ - lib/commands/migrate.rb
25
36
  - lib/commands/push.rb
26
37
  - lib/commands/tumble.rb
27
38
  - lib/rubygems_plugin.rb
@@ -32,9 +43,14 @@ licenses: []
32
43
 
33
44
  post_install_message: |+
34
45
 
35
- =======================================================================
36
- Thanks for installing Gemcutter! To get started, please run: gem tumble
37
- =======================================================================
46
+ ========================================================================
47
+ Thanks for installing Gemcutter! You can now run:
48
+
49
+ gem tumble use Gemcutter as your primary RubyGem source
50
+ gem push publish your gems for the world to use and enjoy
51
+ gem migrate take over your gem from RubyForge on Gemcutter
52
+
53
+ ========================================================================
38
54
 
39
55
  rdoc_options:
40
56
  - --charset=UTF-8
@@ -55,9 +71,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
71
  requirements: []
56
72
 
57
73
  rubyforge_project: gemcutter
58
- rubygems_version: 1.3.4
74
+ rubygems_version: 1.3.3
59
75
  signing_key:
60
76
  specification_version: 3
61
77
  summary: Awesome gem hosting
62
- test_files: []
63
-
78
+ test_files:
79
+ - test/command_helper.rb
80
+ - test/unit/commands/migrate_command_test.rb
81
+ - test/unit/commands/tumble_command_test.rb
82
+ - test/unit/commands/push_command_test.rb
83
+ - test/unit/commands/abstract_command_test.rb