rubygems-source-cli 0.0.1

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.
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: []