rubygems-source-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rubygems-source-cli_patches.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ rubygems-source-cli ![travis-ci](https://secure.travis-ci.org/textgoeshere/rubygems-source-cli.png)
2
+ ===================
3
+
4
+ This is a collection of dirty, dirty patches for `gem push` and `gem
5
+ yank`:
6
+
7
+ * When you do not supply an API key and you are not using
8
+ `rubygems.org`, you are not prompted to sign into `rubygems.org`
9
+ * `gem yank` accepts `--host [HOST]` and `--key [KEY]` options
10
+
11
+ Usage
12
+ -----
13
+
14
+ API keys should be stored in YAML format in `$HOME/.gem/credentials`:
15
+
16
+ ---
17
+ :rubygems_api_key: 198dbad38sadasd87
18
+ :another_key: 2897234987bsdb90834
19
+
20
+ Then specify `--host` and `--key` options when pushing/yanking:
21
+
22
+ $ gem push mygem-1.0.0.gem --host https://example.com --key another_key
23
+ $ gem yank mygem-1.0.0.gem --host https://example.com --key another_key
24
+
25
+ Install
26
+ -------
27
+
28
+ * `gem install rubygems-source-cli`
29
+
30
+ or add it to your `Gemfile`:
31
+
32
+ * `gem "rubygems-source-cli"`
33
+
34
+ Development
35
+ -----------
36
+
37
+ * Source hosted at [GitHub](https://github.com/kapoq/rubygems-source-cli)
38
+ * Report issues/Questions/Feature requests on [GitHub Issues](https://github.com/kapoq/rubygems-source-cli)
39
+ * CI at [Travis](http://travis-ci.org/#!/textgoeshere/rubygems-source-cli)
40
+
41
+ Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
42
+ you make.
43
+
44
+ ### Testing ###
45
+
46
+ $ rake
47
+
48
+ Related projects
49
+ ----------------
50
+
51
+ * [rubygems-source](https://github.com/kapoq/rubygems-source):
52
+ remote source server for Rubygems that implements the core Rubygems gem source web API
53
+ * [rubygems-source-features](https://github.com/kapoq/rubygems-source-features):
54
+ Cucumber features for Rubygems sources
55
+ * [rubygems.org](https://github.com/rubygems/rubygems.org):
56
+ Daddy
57
+ * [geminabox](https://github.com/cwninja/geminabox):
58
+ Very similar project, no `gem yank`, no tests of any kind
59
+ * [sinatra-rubygems](https://github.com/jnewland/sinatra-rubygems):
60
+ Replacement for `gem server` - no `gem push`, `gem yank` or resolver
61
+
62
+ Author
63
+ ------
64
+
65
+ [Dave Nolan](https://github.com/textgoeshere)
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ require 'cucumber/rake/task'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ Cucumber::Rake::Task.new(:features) do |t|
8
+ t.cucumber_opts = "features --format pretty"
9
+ end
10
+
11
+ task :default => [:spec, :features]
@@ -0,0 +1,29 @@
1
+ Feature: per-source API authentication
2
+ In order maintain a thin veneer of security
3
+ As a gem developer
4
+ I want to use the correct key to authenticate with Rubygems sources
5
+
6
+ Scenario: authenticate with Rubygems.org with a rubygems.org api key
7
+ Given I have a gem credentials file with a valid rubygems.org api key
8
+ And a gem package named "foo.gem"
9
+ When I run `gem push foo.gem`
10
+ Then I am not prompted to sign into rubygems.org
11
+ Then I am authenticated with host "https://rubygems.org"
12
+
13
+ Scenario: authenticate with custom api key
14
+ Given I have a gem credentials file with a valid api key for host "other.org"
15
+ And a gem package named "foo.gem"
16
+ When I run `gem push foo.gem --host https://other.org --key other.org`
17
+ Then I am authenticated with host "https://other.org"
18
+
19
+ Scenario: prompted to enter rubygems.org credentials when pushing to rubygems.org without an API key
20
+ Given I have no stored gem credentials
21
+ And a gem package named "foo.gem"
22
+ When I run `gem push foo.gem`
23
+ Then I am prompted to sign into rubygems.org
24
+
25
+ Scenario: not prompted to enter unnecessary rubygems.org credentials
26
+ Given I have no stored gem credentials
27
+ And a gem package named "foo.gem"
28
+ When I run `gem push foo.gem --host https://notrubygems.org`
29
+ Then I am not prompted to sign into rubygems.org
@@ -0,0 +1,5 @@
1
+ Feature: require source option for gem push and yank
2
+ In order to ensure my code is only shared with the people I want
3
+ As a gem developer
4
+ I want to be forced to specify the Rubygems source explicitly
5
+
@@ -0,0 +1,23 @@
1
+ When /^I read the help for the patched commands$/ do
2
+ @output = {}
3
+ Rubygems::Source::CLI::COMMANDS.each do |command|
4
+ run_simple("gem help #{command}")
5
+ @output[command] = all_stdout
6
+ end
7
+ end
8
+
9
+ When /^I run the patched commands$/ do
10
+ @output = {}
11
+ Rubygems::Source::CLI::COMMANDS.each do |command|
12
+ # Don't want wait for the command to execute successfully,
13
+ # so force an error by passing an invalid option
14
+ run_simple("gem #{command} --invalid-option-to-force-error", false)
15
+ @output[command] = all_output
16
+ end
17
+ end
18
+
19
+ Then /^I see a warning they are patched$/ do
20
+ @output.each do |cmd, s|
21
+ unescape(s).should include("patched by rubygems-source-cli")
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ Given /^a gem package named "([^"]*)"$/ do |package_name|
2
+ write_file(package_name, "fake")
3
+ end
4
+
5
+ Given /^I have a gem credentials file with a valid rubygems\.org api key$/ do
6
+ @key = create_valid_api_key("rubygems_api_key")
7
+ end
8
+
9
+ Given /^I have a gem credentials file with a valid api key for host "([^"]*)"$/ do |host|
10
+ @key = create_valid_api_key(host)
11
+ end
12
+
13
+ Given /^I have no stored gem credentials$/ do
14
+ delete_gem_credentials
15
+ end
@@ -0,0 +1,11 @@
1
+ Then /^I am authenticated with host "([^"]*)"$/ do |host|
2
+ assert_partial_output("Authenticated successfully with #{host}", all_output)
3
+ end
4
+
5
+ Then /^I am prompted to sign into rubygems\.org$/ do
6
+ assert_partial_output("Enter your RubyGems.org credentials.", all_output)
7
+ end
8
+
9
+ Then /^I am not prompted to sign into rubygems\.org$/ do
10
+ assert_no_partial_output("Enter your RubyGems.org credentials.", all_output)
11
+ end
@@ -0,0 +1,11 @@
1
+ module CredentialsHelper
2
+ def create_valid_api_key(name)
3
+ write_file("credentials", ":#{name}: valid_key_for_#{name}")
4
+ end
5
+
6
+ def delete_gem_credentials
7
+ remove_file("credentials") if File.exists?("credentials")
8
+ end
9
+ end
10
+
11
+ World(CredentialsHelper)
@@ -0,0 +1,9 @@
1
+ ENV["RUBY_ENV"] ||= "test"
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ Bundler.setup
6
+ require 'rubygems-source-cli'
7
+ require 'aruba/cucumber'
8
+
9
+
@@ -0,0 +1,12 @@
1
+ Feature: warn commands are patched
2
+ In order to manage a shitload of dependencies
3
+ As a developer
4
+ I want to be reminded that I have patched gem commands
5
+
6
+ Scenario: see warning in help
7
+ When I read the help for the patched commands
8
+ Then I see a warning they are patched
9
+
10
+ Scenario: see warning on execute
11
+ When I run the patched commands
12
+ Then I see a warning they are patched
@@ -0,0 +1,9 @@
1
+ Feature: yank gem from non-Rubygems.org source
2
+ In order to defend my team from sub-awesome code
3
+ As a gem developer
4
+ I want to yank a bad gem from our local Rubygems source server
5
+
6
+ Scenario: yank gem from custom Rubygems source
7
+ Given I have a gem credentials file with a valid api key for host "other.org"
8
+ When I run `gem yank mygem.gem -v 1.0.0 --host https://other.org --key other.org`
9
+ And I am authenticated with host "https://other.org"
@@ -0,0 +1,12 @@
1
+ module Rubygems
2
+ module Source
3
+ module CLI
4
+ autoload :VERSION, "rubygems-source-cli/version"
5
+ autoload :CommandPatch, "rubygems-source-cli/command_patch"
6
+
7
+ COMMANDS = %w(yank push server)
8
+ end
9
+ end
10
+ end
11
+
12
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "test", "test_helper")) if ENV['RUBY_ENV'] == 'test'
@@ -0,0 +1,11 @@
1
+ module Rubygems::Source::CLI
2
+ module CommandPatch
3
+ def initialize(*args)
4
+ warning = "* This command is patched by rubygems-source-cli v#{Rubygems::Source::CLI::VERSION} *"
5
+ say "\n" + (%w(*) * warning.length).join
6
+ say warning
7
+ say (%w(*) * warning.length).join + "\n\n"
8
+ super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ class Gem::Commands::PushCommand < Gem::Command
2
+ RUBYGEMS_HOST = "rubygems.org"
3
+
4
+ def execute
5
+ sign_into_rubygems if host_is_rubygems? && !Gem.configuration.rubygems_api_key
6
+ send_gem get_one_gem_name
7
+ end
8
+
9
+ def sign_into_rubygems
10
+ sign_in
11
+ end
12
+
13
+ private
14
+
15
+ def host_is_rubygems?
16
+ uri = ENV['RUBYGEMS_HOST'] || options[:host] || Gem.host
17
+ URI.parse(uri).host == RUBYGEMS_HOST
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module Rubygems::Source::CLI
2
+ module ServerCommand
3
+ end
4
+ end
@@ -0,0 +1,69 @@
1
+ class Gem::Commands::YankCommand < Gem::Command
2
+ RUBYGEMS_HOST = "rubygems.org"
3
+
4
+ def initialize(*args)
5
+ super 'yank', description
6
+ add_version_option("remove")
7
+ add_platform_option("remove")
8
+ add_option('--undo') do |value, options|
9
+ options[:undo] = true
10
+ end
11
+ add_key_option
12
+ add_option(
13
+ '--host HOST',
14
+ 'Yank from another gemcutter-compatible host'
15
+ ) do |value, options|
16
+ options[:host] = value
17
+ end
18
+ end
19
+
20
+ def execute
21
+ sign_into_rubygems if host_is_rubygems? && !Gem.configuration.rubygems_api_key
22
+ version = get_version_from_requirements(options[:version])
23
+ platform = get_platform_from_requirements(options)
24
+
25
+ if !version.nil?
26
+ if options[:undo]
27
+ unyank_gem(version, platform)
28
+ else
29
+ yank_gem(version, platform)
30
+ end
31
+ else
32
+ say "A version argument is required: #{usage}"
33
+ terminate_interaction
34
+ end
35
+ end
36
+
37
+ def yank_gem(version, platform)
38
+ say "Yanking gem from #{options[:host] || 'Rubygems.org'}..."
39
+ yank_api_request(:delete, version, platform, "api/v1/gems/yank")
40
+ end
41
+
42
+ def unyank_gem(version, platform)
43
+ say "Unyanking gem from #{options[:host] || 'Rubygems.org'}..."
44
+ yank_api_request(:put, version, platform, "api/v1/gems/unyank")
45
+ end
46
+
47
+ def sign_into_rubygems
48
+ sign_in
49
+ end
50
+
51
+ private
52
+
53
+ def host_is_rubygems?
54
+ uri = ENV['RUBYGEMS_HOST'] || options[:host] || Gem.host
55
+ URI.parse(uri).host == RUBYGEMS_HOST
56
+ end
57
+
58
+ def yank_api_request(method, version, platform, api)
59
+ args = [method, "api/v1/gems"]
60
+ args << options[:host] if options[:host]
61
+
62
+ name = get_one_gem_name
63
+ response = rubygems_api_request(*args) do |request|
64
+ request.add_field("Authorization", api_key)
65
+ request.set_form_data({'gem_name' => name, 'version' => version, 'platform' => platform})
66
+ end
67
+ say response.body
68
+ end
69
+ end
@@ -0,0 +1,7 @@
1
+ module Rubygems
2
+ module Source
3
+ module CLI
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems/command_manager'
2
+ require 'rubygems/command'
3
+ require 'rubygems-source-cli'
4
+
5
+ #
6
+ # Load files and apply patches for each command
7
+ #
8
+ Rubygems::Source::CLI::COMMANDS.each do |cmd|
9
+ filename = "#{cmd}_command"
10
+ const_name = cmd.capitalize.gsub(/_(.)/) { $1.upcase } << "Command"
11
+
12
+ require "rubygems/commands/#{filename}"
13
+ require "rubygems-source-cli/commands/#{filename}"
14
+
15
+ klass = Gem::Commands.const_get(const_name)
16
+ klass.send(:include, Rubygems::Source::CLI::CommandPatch)
17
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rubygems-source-cli/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rubygems-source-cli"
7
+ s.version = Rubygems::Source::CLI::VERSION
8
+ s.authors = ["dave@kapoq.com"]
9
+ s.email = ["dave@kapoq.com"]
10
+ s.homepage = "https://github.com/kapoq/rubygems-source-cli"
11
+ s.summary = "Patches for gem serve, gem push, gem yank, and some utilities"
12
+ s.description = "Patches for gem serve, gem push, gem yank, and some utilities to allow use of non-Rubygems.org gem sources"
13
+
14
+ s.add_development_dependency "cucumber"
15
+ s.add_development_dependency "aruba"
16
+ s.add_development_dependency "webmock"
17
+ s.add_development_dependency "rspec"
18
+ s.add_development_dependency "guard-rspec"
19
+ s.add_development_dependency "rake"
20
+ s.add_development_dependency "capybara"
21
+ s.add_development_dependency "builder"
22
+ s.add_development_dependency "gemcutter"
23
+ if RUBY_PLATFORM =~ /linux/
24
+ s.add_development_dependency "rb-inotify"
25
+ s.add_development_dependency "libnotify"
26
+ end
27
+
28
+ s.files = `git ls-files`.split("\n")
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
+ s.require_paths = ["lib"]
32
+ end
@@ -0,0 +1,27 @@
1
+ require 'webmock'
2
+
3
+ #
4
+ # Disable all net access
5
+ #
6
+ WebMock.disable_net_connect!
7
+
8
+ #
9
+ # Stub out expected requests
10
+ #
11
+ include WebMock::API
12
+
13
+ stub_request(:post, "https://rubygems.org/api/v1/gems").with(:headers => {'Authorization'=>'valid_key_for_rubygems_api_key'}).to_return(:status => 200, :body => "Authenticated successfully with https://rubygems.org", :headers => {})
14
+
15
+ stub_request(:post, "https://other.org/api/v1/gems").with(:headers => {'Authorization'=>'valid_key_for_other.org'}).to_return(:status => 200, :body => "Authenticated successfully with https://other.org", :headers => {})
16
+
17
+
18
+ stub_request(:delete, "https://other.org/api/v1/gems").with(:headers => {'Authorization'=>'valid_key_for_other.org'}).to_return(:status => 200, :body => "Authenticated successfully with https://other.org", :headers => {})
19
+
20
+ #
21
+ # Overwrite credentials_path so Gem users test credentials file created by Aruba
22
+ #
23
+ class Gem::ConfigFile
24
+ def credentials_path
25
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "tmp", "aruba", "credentials"))
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubygems-source-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - dave@kapoq.com
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-21 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cucumber
16
+ requirement: &22041280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *22041280
25
+ - !ruby/object:Gem::Dependency
26
+ name: aruba
27
+ requirement: &22040740 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *22040740
36
+ - !ruby/object:Gem::Dependency
37
+ name: webmock
38
+ requirement: &22040220 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *22040220
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &22039760 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *22039760
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard-rspec
60
+ requirement: &22039220 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *22039220
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: &22038700 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *22038700
80
+ - !ruby/object:Gem::Dependency
81
+ name: capybara
82
+ requirement: &22038280 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *22038280
91
+ - !ruby/object:Gem::Dependency
92
+ name: builder
93
+ requirement: &22037820 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *22037820
102
+ - !ruby/object:Gem::Dependency
103
+ name: gemcutter
104
+ requirement: &22037280 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *22037280
113
+ - !ruby/object:Gem::Dependency
114
+ name: rb-inotify
115
+ requirement: &22036780 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *22036780
124
+ - !ruby/object:Gem::Dependency
125
+ name: libnotify
126
+ requirement: &22036240 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *22036240
135
+ description: Patches for gem serve, gem push, gem yank, and some utilities to allow
136
+ use of non-Rubygems.org gem sources
137
+ email:
138
+ - dave@kapoq.com
139
+ executables: []
140
+ extensions: []
141
+ extra_rdoc_files: []
142
+ files:
143
+ - .gitignore
144
+ - Gemfile
145
+ - README.md
146
+ - Rakefile
147
+ - features/per-source_api_authentication.feature
148
+ - features/require_source_option_for_gem_push_and_yank.feature
149
+ - features/step_definitions/cli_steps.rb
150
+ - features/step_definitions/gem_steps.rb
151
+ - features/step_definitions/response_steps.rb
152
+ - features/support/credentials_helper.rb
153
+ - features/support/env.rb
154
+ - features/warn_commands_are_patched.feature
155
+ - features/yank_from_non-rubygems.org_source.feature
156
+ - lib/rubygems-source-cli.rb
157
+ - lib/rubygems-source-cli/command_patch.rb
158
+ - lib/rubygems-source-cli/commands/push_command.rb
159
+ - lib/rubygems-source-cli/commands/server_command.rb
160
+ - lib/rubygems-source-cli/commands/yank_command.rb
161
+ - lib/rubygems-source-cli/version.rb
162
+ - lib/rubygems_plugin.rb
163
+ - rubygems-source-cli.gemspec
164
+ - test/test_helper.rb
165
+ homepage: https://github.com/kapoq/rubygems-source-cli
166
+ licenses: []
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ none: false
173
+ requirements:
174
+ - - ! '>='
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ required_rubygems_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ! '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubyforge_project:
185
+ rubygems_version: 1.8.11
186
+ signing_key:
187
+ specification_version: 3
188
+ summary: Patches for gem serve, gem push, gem yank, and some utilities
189
+ test_files: []