gemfury 0.10.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 624ab4a41068c6d17c63693ff3bc4de20641ee87390f68df9f7d02c29a59e16e
4
+ data.tar.gz: f4657867345ca219161a3090be0fb2ba19c475cb3fb33ac637213aa0c32916c5
5
+ SHA512:
6
+ metadata.gz: 569f391a1d8230204d9b1778042a57e53a72afae523ae7f1b4646971ad2db1918dc1260792f0fce000e995619d78f5c2bc3ca013945883cb01c6292463694219
7
+ data.tar.gz: f3906e7e9b1e360ba75f8615f5728009b3e8c01915be185777ea2fdef9d1207990abe3c86f405a18e8275461eef334efb8c1c738ceb62eb74765d63d24fa063e
@@ -0,0 +1,62 @@
1
+ Gemfury CLI
2
+ ===========
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/gemfury.svg)](http://badge.fury.io/rb/gemfury)
5
+ [![Build Status](https://secure.travis-ci.org/gemfury/gemfury.svg?branch=master)](https://travis-ci.org/gemfury/gemfury)
6
+ [![Code Climate](https://codeclimate.com/github/gemfury/gemfury/badges/gpa.svg)](https://codeclimate.com/github/gemfury/gemfury)
7
+
8
+ This is the Gemfury CLI used to manage your Gemfury packages from the command line. If you're
9
+ familiar with the service and want to jump straight into command line action, please proceed to
10
+ the [CLI documentation](https://gemfury.com/help/gemfury-cli).
11
+
12
+ Gemfury is your personal cloud for your private and custom RubyGems, Python packages, and NPM
13
+ modules. Once you upload your packages and enable Gemfury as a source, you can securely deploy
14
+ any package to any host. It's simple, reliable, and hassle-free.
15
+
16
+
17
+ ### Introduction to Gemfury
18
+ * [Gemfury homepage](https://gemfury.com/)
19
+ * [Getting started with Gemfury](https://gemfury.com/help/getting-started)
20
+
21
+ ### Using Gemfury CLI
22
+ * [CLI documentation](https://gemfury.com/help/gemfury-cli)
23
+ * [Uploading private packages](https://gemfury.com/help/gemfury-cli#uploading-packages)
24
+ * [Manage collaborators](https://gemfury.com/help/gemfury-cli#collaboration)
25
+
26
+ ### Putting Gemfury to work
27
+ * [Install private RubyGems](https://gemfury.com/help/install-gems)
28
+ * [Install private NPM modules](https://gemfury.com/help/npm-registry)
29
+ * [Install private Python packages](https://gemfury.com/help/pypi-server)
30
+ * [Install private Composer packages](https://gemfury.com/help/php-composer-server)
31
+ * [Private RubyGems on Heroku](https://gemfury.com/help/private-gems-on-heroku)
32
+
33
+ ## Contribution and Improvements
34
+
35
+ Please [email us](mailto:support@gemfury.com) if we've missed some key functionality or you have problems installing the CLI client. Better yet, fork the code, make the changes, and submit a pull request to speed things along.
36
+
37
+ ### Submitting updates
38
+
39
+ If you would like to contribute to this project, just do the following:
40
+
41
+ 1. Fork the repo on Github.
42
+ 2. Add your features and make commits to your forked repo.
43
+ 3. Make a pull request to this repo.
44
+ 4. Review will be done and changes will be requested.
45
+ 5. Once changes are done or no changes are required, pull request will be merged.
46
+ 6. The next release will have your changes in it.
47
+
48
+ Please take a look at the issues page if you want to get started.
49
+
50
+ ### Feature requests
51
+
52
+ If you think it would be nice to have a particular feature that is presently not implemented, we would love
53
+ to hear that and consider working on it. Just open an issue in Github.
54
+
55
+ ### Dependency conflicts
56
+
57
+ Over time, dependencies for this gem will get stale and may interfere with your other gems. Please let us know if you run into this and we will re-test our gem with the new version of the dependency and update the _gemspec_.
58
+
59
+
60
+ ## Questions
61
+
62
+ Please email support@gemfury.com or file a Github Issue if you have any other questions or problems.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'rubygems'
7
+ require 'gemfury'
8
+ require 'gemfury/command'
9
+
10
+ Gemfury::Command::App.start
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ exec(File.expand_path('../fury', __FILE__), *ARGV)
@@ -0,0 +1,32 @@
1
+ # This is a Faraday adapter that bypasses Faraday's response body
2
+ # processing and streams body to STDOUT for text requests
3
+
4
+ class Faraday::Adapter
5
+ class FuryHttp < NetHttp
6
+ def perform_request(http, env)
7
+ accept = env.request_headers['Accept']
8
+ return super if accept !~ /text\z/
9
+
10
+ # Stream response body to STDOUT on success
11
+ http.request(create_request(env)) do |resp|
12
+ unless resp.is_a?(Net::HTTPSuccess)
13
+ resp.body # Cache error body
14
+ else
15
+ resp.read_body do |chunk|
16
+ $stdout.print(chunk)
17
+ $stdout.flush
18
+ end
19
+
20
+ # Prevent #body from calling #read_body again
21
+ klass = (class << resp; self; end)
22
+ klass.send(:define_method, :body) { nil }
23
+ end
24
+
25
+ # Return response to NetHttp adapter
26
+ return resp
27
+ end
28
+ end
29
+ end
30
+
31
+ register_middleware(:fury_http => FuryHttp)
32
+ end
@@ -0,0 +1,34 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module Faraday
5
+ # @private
6
+ class Request::MultipartWithFile < Faraday::Middleware
7
+ def call(env)
8
+ if env[:body].is_a?(Hash)
9
+ env[:body].each do |key, value|
10
+ if value.is_a?(File)
11
+ env[:body][key] = Faraday::UploadIO.new(value, mime_type(value), value.path)
12
+ end
13
+ end
14
+ end
15
+
16
+ @app.call(env)
17
+ end
18
+
19
+ private
20
+
21
+ def mime_type(file)
22
+ case file.path
23
+ when /\.jpe?g/i
24
+ 'image/jpeg'
25
+ when /\.gif$/i
26
+ 'image/gif'
27
+ when /\.png$/i
28
+ 'image/png'
29
+ else
30
+ 'application/octet-stream'
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,53 @@
1
+ gem "multi_json", "~> 1.10"
2
+ gem "faraday", ">= 0.9.0", "< 0.16.0.pre"
3
+ gem "netrc", ">= 0.10.0", "< 0.12.0.pre"
4
+
5
+ require 'time'
6
+ require 'cgi'
7
+ require 'uri'
8
+ require 'netrc'
9
+ require 'multi_json'
10
+ require 'faraday'
11
+ require 'faraday/adapter/fury_http'
12
+ require 'faraday/request/multipart_with_file'
13
+
14
+ require 'gemfury/version'
15
+ require 'gemfury/const'
16
+ require 'gemfury/error'
17
+ require 'gemfury/platform'
18
+ require 'gemfury/configuration'
19
+
20
+ require 'gemfury/client/filters'
21
+ require 'gemfury/client/middleware'
22
+ require 'gemfury/client'
23
+
24
+ module Gemfury
25
+ extend Configuration
26
+ class << self
27
+ # Alias for Gemfury::Client.new
28
+ #
29
+ # @return [Gemfury::Client]
30
+ def new(options={})
31
+ Gemfury::Client.new(options)
32
+ end
33
+
34
+ # Delegate to Gemfury::Client
35
+ def method_missing(method, *args, &block)
36
+ return super unless new.respond_to?(method)
37
+ new.send(method, *args, &block)
38
+ end
39
+
40
+ def respond_to?(method, include_private = false)
41
+ new.respond_to?(method, include_private) || super(method, include_private)
42
+ end
43
+ end
44
+ end
45
+
46
+ class Hash
47
+ # Access nested hashes as a period-separated path
48
+ def path(path, separator = '.')
49
+ path.split(separator).inject(self) do |hash, part|
50
+ hash.is_a?(Hash) ? hash[part] : nil
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,211 @@
1
+ module Gemfury
2
+ class Client
3
+ include Gemfury::Client::Filters
4
+ attr_accessor *Configuration::VALID_OPTIONS_KEYS
5
+
6
+ # Creates a new API
7
+ def initialize(options={})
8
+ options = Gemfury.options.merge(options)
9
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
10
+ send("#{key}=", options[key])
11
+ end
12
+ end
13
+
14
+ # Get the information for the current account
15
+ def account_info
16
+ ensure_ready!(:authorization)
17
+ response = connection.get('users/me')
18
+ checked_response_body(response)
19
+ end
20
+
21
+ # Get the information for the current account
22
+ def accounts
23
+ ensure_ready!(:authorization)
24
+ response = connection.get('accounts')
25
+ checked_response_body(response)
26
+ end
27
+
28
+ # Uploading a gem file
29
+ def push_gem(file, options = {})
30
+ ensure_ready!(:authorization)
31
+ push_api = connection(:url => self.pushpoint)
32
+ response = push_api.post('uploads', options.merge(:file => file))
33
+ checked_response_body(response)
34
+ end
35
+
36
+ # List available gems
37
+ def list(options = {})
38
+ ensure_ready!(:authorization)
39
+ response = connection.get('gems', options)
40
+ checked_response_body(response)
41
+ end
42
+
43
+ # List versions for a gem
44
+ def versions(name, options = {})
45
+ ensure_ready!(:authorization)
46
+ url = "gems/#{escape(name)}/versions"
47
+ response = connection.get(url, options)
48
+ checked_response_body(response)
49
+ end
50
+
51
+ # Delete a gem version
52
+ def yank_version(name, version, options = {})
53
+ ensure_ready!(:authorization)
54
+ url = "gems/#{escape(name)}/versions/#{escape(version)}"
55
+ response = connection.delete(url, options)
56
+ checked_response_body(response)
57
+ end
58
+
59
+ # LEGACY: Authentication token via email/password
60
+ def get_access_token(*args)
61
+ login(*args)['token']
62
+ end
63
+
64
+ # Get authentication info via email/password
65
+ def login(email, password, opts = {})
66
+ ensure_ready!
67
+ opts = opts.merge(:email => email, :password => password)
68
+ checked_response_body(connection.post('login', opts))
69
+ end
70
+
71
+ # Invalidate session token
72
+ def logout
73
+ ensure_ready!(:authorization)
74
+ response = connection.post('logout')
75
+ checked_response_body(response)
76
+ end
77
+
78
+ # List collaborators for this account
79
+ def list_collaborators(options = {})
80
+ ensure_ready!(:authorization)
81
+ response = connection.get('collaborators', options)
82
+ checked_response_body(response)
83
+ end
84
+
85
+ # Add a collaborator to the account
86
+ def add_collaborator(login, options = {})
87
+ ensure_ready!(:authorization)
88
+ url = "collaborators/#{escape(login)}"
89
+ response = connection.put(url, options)
90
+ checked_response_body(response)
91
+ end
92
+
93
+ # Remove a collaborator to the account
94
+ def remove_collaborator(login, options = {})
95
+ ensure_ready!(:authorization)
96
+ url = "collaborators/#{escape(login)}"
97
+ response = connection.delete(url, options)
98
+ checked_response_body(response)
99
+ end
100
+
101
+ # List Git repos for this account
102
+ def git_repos(options = {})
103
+ ensure_ready!(:authorization)
104
+ response = connection.get(git_repo_path, options)
105
+ checked_response_body(response)
106
+ end
107
+
108
+ # Update repository name and settings
109
+ def git_update(repo, options = {})
110
+ ensure_ready!(:authorization)
111
+ response = connection.patch(git_repo_path(repo), options)
112
+ checked_response_body(response)
113
+ end
114
+
115
+ # Reset repository to initial state
116
+ def git_reset(repo, options = {})
117
+ ensure_ready!(:authorization)
118
+ response = connection.delete(git_repo_path(repo), options)
119
+ checked_response_body(response)
120
+ end
121
+
122
+ # Rebuild Git repository package
123
+ def git_rebuild(repo, options = {})
124
+ ensure_ready!(:authorization)
125
+ url = "#{git_repo_path(repo)}/builds"
126
+ api = connection(:api_format => :text)
127
+ checked_response_body(api.post(url, options))
128
+ end
129
+
130
+ private
131
+ def escape(str)
132
+ CGI.escape(str)
133
+ end
134
+
135
+ def git_repo_path(*args)
136
+ rest = args.map { |a| escape(a) }
137
+ ['git/repos', self.account || 'me'].concat(rest).join('/')
138
+ end
139
+
140
+ def connection(options = {})
141
+ # The 'Accept' HTTP header for API versioning
142
+ http_accept = begin
143
+ v = options.delete(:api_version) || self.api_version
144
+ f = options.delete(:api_format) || :json
145
+ "application/vnd.fury.v#{v.to_i}+#{f}"
146
+ end
147
+
148
+ # Faraday client options
149
+ options = {
150
+ :url => self.endpoint,
151
+ :params => {},
152
+ :headers => {
153
+ :accept => http_accept,
154
+ :user_agent => self.user_agent,
155
+ :x_gem_version => Gemfury::VERSION,
156
+ }.merge(options.delete(:headers) || {})
157
+ }.merge(options)
158
+
159
+ if self.user_api_key
160
+ options[:headers][:authorization] = self.user_api_key
161
+ end
162
+
163
+ if self.account
164
+ options[:params][:as] = self.account
165
+ end
166
+
167
+ Faraday.new(options) do |builder|
168
+ builder.use Faraday::Request::MultipartWithFile
169
+ builder.use Faraday::Request::Multipart
170
+ builder.use Faraday::Request::UrlEncoded
171
+ builder.use ParseJson
172
+ builder.use Handle503
173
+ builder.adapter :fury_http
174
+ end
175
+ end
176
+
177
+ def checked_response_body(response)
178
+ if response.success?
179
+ return response.body
180
+ else
181
+ error = (response.body || {})['error'] || {}
182
+ error_class = case error['type']
183
+ when 'Forbidden' then Gemfury::Forbidden
184
+ when 'GemVersionError' then Gemfury::InvalidGemVersion
185
+ when 'InvalidGemFile' then Gemfury::CorruptGemFile
186
+ when 'DupeVersion' then Gemfury::DupeVersion
187
+ else
188
+ case response.status
189
+ when 401 then Gemfury::Unauthorized
190
+ when 403 then Gemfury::Forbidden
191
+ when 404 then Gemfury::NotFound
192
+ when 409 then Gemfury::Conflict
193
+ when 503 then Gemfury::TimeoutError
194
+ else Gemfury::Error
195
+ end
196
+ end
197
+
198
+ raise(error_class, error['message'])
199
+ end
200
+ end
201
+
202
+ def s3_put_file(uri, file)
203
+ Faraday::Connection.new(uri) do |f|
204
+ f.adapter :net_http
205
+ end.put(uri, file, {
206
+ :content_length => file.stat.size.to_s,
207
+ :content_type => ''
208
+ })
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,18 @@
1
+ module Gemfury
2
+ class Client
3
+ module Filters
4
+
5
+ private
6
+ def ensure_ready!(*args)
7
+ # Ensure authorization
8
+ if args.include?(:authorization)
9
+ raise Unauthorized unless authenticated?
10
+ end
11
+ end
12
+
13
+ def authenticated?
14
+ self.user_api_key && !self.user_api_key.empty?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module Gemfury
2
+ class Client
3
+ class Handle503 < Faraday::Middleware
4
+ def call(env)
5
+ # This prevents errors in ParseJson
6
+ @app.call(env).on_complete do |out|
7
+ out[:body] = '' if out[:status] == 503
8
+ end
9
+ end
10
+ end
11
+
12
+ class ParseJson < Faraday::Response::Middleware
13
+ def parse(body)
14
+ body =~ /\A\s*\z/ ? nil : MultiJson.decode(body)
15
+ end
16
+
17
+ def on_complete(response)
18
+ ok = response.request_headers['Accept'] =~ /json\z/
19
+ response.body = parse(response.body) if ok
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ gem "highline", ">= 1.6.0", "< 2.1.0.pre"
2
+ gem "thor", ">= 0.14.0", "< 1.0.0.pre"
3
+
4
+ require 'thor'
5
+ require 'yaml'
6
+ require 'highline'
7
+ require 'fileutils'
8
+
9
+ module Gemfury::Command; end
10
+
11
+ require 'gemfury/command/authorization'
12
+ require 'gemfury/command/app'
@@ -0,0 +1,295 @@
1
+ class Gemfury::Command::App < Thor
2
+ include Gemfury::Command::Authorization
3
+ UserAgent = "Gemfury CLI #{Gemfury::VERSION}".freeze
4
+ PackageExtensions = %w(gem egg tar.gz tgz nupkg)
5
+
6
+ # Impersonation
7
+ class_option :as, :desc => 'Access an account other than your own'
8
+ class_option :api_token, :desc => 'API token to use for commands'
9
+
10
+ map "-v" => :version
11
+ desc "version", "Show Gemfury version", :hide => true
12
+ def version
13
+ shell.say Gemfury::VERSION
14
+ end
15
+
16
+ ### PACKAGE MANAGEMENT ###
17
+ option :public, :type => :boolean, :desc => "Create as public package"
18
+ desc "push FILE", "Upload a new version of a package"
19
+ def push(*gems)
20
+ with_checks_and_rescues do
21
+ push_files(:push, gems)
22
+ end
23
+ end
24
+
25
+ desc "list", "List your packages"
26
+ def list
27
+ with_checks_and_rescues do
28
+ gems = client.list
29
+ shell.say "\n*** GEMFURY PACKAGES ***\n\n"
30
+
31
+ va = [ %w{ name kind version privacy } ]
32
+ gems.each do |g|
33
+ va << [ g['name'], g['language'],
34
+ g.path('latest_version.version') || 'beta',
35
+ g['private'] ? 'private' : 'public ' ]
36
+ end
37
+
38
+ shell.print_table(va)
39
+ end
40
+ end
41
+
42
+ desc "versions NAME", "List all the package versions"
43
+ def versions(gem_name)
44
+ with_checks_and_rescues do
45
+ versions = client.versions(gem_name)
46
+ shell.say "\n*** #{gem_name.capitalize} Versions ***\n\n"
47
+
48
+ va = []
49
+ va = [ %w{ version uploaded uploaded_by } ]
50
+ versions.each do |v|
51
+ uploaded = Time.parse(v['created_at']).strftime('%F %R %z')
52
+ va << [ v['version'], uploaded, v['created_by']['name'] ]
53
+ end
54
+
55
+ shell.print_table(va)
56
+ end
57
+ end
58
+
59
+ desc "yank NAME", "Delete a package version"
60
+ method_options %w(version -v) => :required
61
+ def yank(gem_name)
62
+ with_checks_and_rescues do
63
+ version = options[:version]
64
+ client.yank_version(gem_name, version)
65
+ shell.say "\n*** Yanked #{gem_name}-#{version} ***\n\n"
66
+ end
67
+ end
68
+
69
+ ### AUTHENTICATION ###
70
+ desc "logout", "Remove Gemfury credentials"
71
+ def logout
72
+ if !has_credentials?
73
+ shell.say "You are logged out"
74
+ elsif shell.yes? "Are you sure you want to log out? [yN]"
75
+ with_checks_and_rescues { client.logout }
76
+ wipe_credentials!
77
+ shell.say "You have been logged out"
78
+ end
79
+ end
80
+
81
+ desc "login", "Save Gemfury credentials"
82
+ def login
83
+ with_checks_and_rescues do
84
+ me = client.account_info['name']
85
+ shell.say %Q(You are logged in as "#{me}"), :green
86
+ end
87
+ end
88
+
89
+ desc "whoami", "Show current user"
90
+ def whoami
91
+ has_credentials? ? self.login : begin
92
+ shell.say %Q(You are not logged in), :green
93
+ end
94
+ end
95
+
96
+ desc "accounts", "Show info about your Gemfury accounts"
97
+ def accounts
98
+ with_checks_and_rescues do
99
+ accounts = client.accounts
100
+
101
+ va = [ %w{ name kind permission } ]
102
+ accounts.each do |a|
103
+ va << [ a['name'], a['type'], a['viewer_permission'].downcase ]
104
+ end
105
+
106
+ shell.print_table(va)
107
+ end
108
+ end
109
+
110
+ ### COLLABORATION MANAGEMENT ###
111
+ map "sharing:add" => 'sharing_add'
112
+ map "sharing:remove" => 'sharing_remove'
113
+
114
+ desc "sharing", "List collaborators"
115
+ def sharing
116
+ with_checks_and_rescues do
117
+ me = client.account_info['username']
118
+ collaborators = client.list_collaborators
119
+ if collaborators.empty?
120
+ shell.say "You (#{me}) are the only collaborator", :green
121
+ else
122
+ shell.say %Q(\n*** Collaborators for "#{me}" ***\n), :green
123
+ usernames = [me] + collaborators.map { |c| c['username'] }
124
+ shell.say usernames.join("\n")
125
+ end
126
+ shell.say "\n"
127
+ end
128
+ end
129
+
130
+ desc "sharing:add EMAIL", "Add a collaborator"
131
+ def sharing_add(username)
132
+ with_checks_and_rescues do
133
+ client.add_collaborator(username)
134
+ shell.say "Invited #{username} as a collaborator"
135
+ end
136
+ end
137
+
138
+ desc "sharing:remove EMAIL", "Remove a collaborator"
139
+ def sharing_remove(username)
140
+ with_checks_and_rescues do
141
+ client.remove_collaborator(username)
142
+ shell.say "Removed #{username} as a collaborator"
143
+ end
144
+ end
145
+
146
+ ### MIGRATION (Pushing directories) ###
147
+ desc "migrate DIR", "Upload all packages within a directory"
148
+ def migrate(*paths)
149
+ with_checks_and_rescues do
150
+ gem_paths = Dir.glob(paths.map do |p|
151
+ if File.directory?(p)
152
+ PackageExtensions.map { |ext| "#{p}/**/*.#{ext}" }
153
+ elsif File.file?(p)
154
+ p
155
+ else
156
+ nil
157
+ end
158
+ end.flatten.compact)
159
+
160
+ if gem_paths.empty?
161
+ die!("Problem: No valid packages found", nil, :migrate)
162
+ else
163
+ shell.say "Found the following packages:"
164
+ gem_paths.each { |p| shell.say " #{File.basename(p)}" }
165
+ if shell.yes? "Upload these files to Gemfury? [yN]", :green
166
+ push_files(:migrate, gem_paths)
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ ### GIT REPOSITORY MANAGEMENT ###
173
+ map "git:list" => 'git_list'
174
+ map "git:reset" => 'git_reset'
175
+ map "git:rename" => 'git_rename'
176
+ map "git:rebuild" => 'git_rebuild'
177
+
178
+ desc "git:list", "List Git repositories"
179
+ def git_list
180
+ with_checks_and_rescues do
181
+ repos = client.git_repos['repos']
182
+ shell.say "\n*** GEMFURY GIT REPOS ***\n\n"
183
+ names = repos.map { |r| r['name'] }
184
+ names.sort.each { |n| shell.say(n) }
185
+ end
186
+ end
187
+
188
+ desc "git:rename", "Rename a Git repository"
189
+ def git_rename(repo, new_name)
190
+ with_checks_and_rescues do
191
+ client.git_update(repo, :repo => { :name => new_name })
192
+ shell.say "Renamed #{repo} repository to #{new_name}\n"
193
+ end
194
+ end
195
+
196
+ desc "git:reset", "Remove a Git repository"
197
+ def git_reset(repo)
198
+ with_checks_and_rescues do
199
+ client.git_reset(repo)
200
+ shell.say "\n*** Yanked #{repo} repository ***\n\n"
201
+ end
202
+ end
203
+
204
+ desc "git:rebuild", "Rebuild a Git repository"
205
+ method_options %w(revision -r) => :string
206
+ def git_rebuild(repo)
207
+ with_checks_and_rescues do
208
+ params = { :revision => options[:revision] }
209
+ shell.say "\n*** Rebuilding #{repo} repository ***\n\n"
210
+ shell.say client.git_rebuild(repo, :build => params)
211
+ end
212
+ end
213
+
214
+ private
215
+ def client
216
+ opts = {}
217
+ opts[:user_api_key] = @user_api_key if @user_api_key
218
+ opts[:account] = options[:as] if options[:as]
219
+ client = Gemfury::Client.new(opts)
220
+ client.user_agent = UserAgent
221
+ return client
222
+ end
223
+
224
+ def with_checks_and_rescues(&block)
225
+ @user_api_key = options[:api_token] if options[:api_token]
226
+ with_authorization(&block)
227
+ rescue Gemfury::InvalidGemVersion => e
228
+ shell.say "You have a deprecated Gemfury client", :red
229
+ if shell.yes? "Would you like to update it now? [yN]"
230
+ exec("gem update gemfury")
231
+ else
232
+ shell.say %q(No problem. You can also run "gem update gemfury")
233
+ end
234
+ rescue Gemfury::Conflict => e
235
+ die!("Oops! Locked for another user. Try again later.", e)
236
+ rescue Gemfury::Forbidden => e
237
+ die!("Oops! You're not allowed to access this", e)
238
+ rescue Gemfury::NotFound => e
239
+ die!("Oops! Doesn't look like this exists", e)
240
+ rescue Gemfury::Error => e
241
+ die!("Oops! %s" % e.message, e)
242
+ rescue StandardError => e
243
+ die!("Oops! Something went wrong. Please contact support.", e)
244
+ end
245
+
246
+ def push_files(command, gem_paths)
247
+ files = gem_paths.map do |g|
248
+ g.is_a?(String) ? File.new(g) : g rescue nil
249
+ end.compact
250
+
251
+ if files.empty?
252
+ die!("Problem: No valid packages found", nil, command)
253
+ end
254
+
255
+ push_options = { }
256
+ unless options[:public].nil?
257
+ push_options[:public] = options[:public]
258
+ end
259
+
260
+ error_ex = nil
261
+
262
+ # Let's get uploading
263
+ files.each do |file|
264
+ begin
265
+ shell.say "Uploading #{File.basename(file.path)} "
266
+ client.push_gem(file, push_options)
267
+ shell.say "- done"
268
+ rescue Gemfury::CorruptGemFile => e
269
+ shell.say "- problem processing this package", :red
270
+ error_ex = e
271
+ rescue Gemfury::DupeVersion => e
272
+ shell.say "- this version already exists", :red
273
+ error_ex = e
274
+ rescue Gemfury::TimeoutError, Errno::EPIPE => e
275
+ shell.say "- this file is too much to handle", :red
276
+ shell.say " Visit http://www.gemfury.com/large-package for more info"
277
+ error_ex = e
278
+ rescue => e
279
+ shell.say "- oops", :red
280
+ error_ex = e
281
+ end
282
+ end
283
+
284
+ unless error_ex.nil?
285
+ die!('There was a problem uploading at least 1 package', error_ex)
286
+ end
287
+ end
288
+
289
+ def die!(msg, err = nil, command = nil)
290
+ shell.say msg, :red
291
+ help(command) if command
292
+ shell.say %Q(#{err.class.name}: #{err}\n#{err.backtrace.join("\n")}) if err && ENV['DEBUG']
293
+ exit(1)
294
+ end
295
+ end
@@ -0,0 +1,79 @@
1
+ module Gemfury::Command::Authorization
2
+ include Gemfury::Platform
3
+
4
+ def wipe_credentials!
5
+ FileUtils.rm(config_path, :force => true) # never raises exception
6
+ each_netrc_host { |h| netrc_conf.delete(h) }
7
+ netrc_conf.save
8
+ end
9
+
10
+ def has_credentials?
11
+ !!netrc_conf[netrc_api_host] ||
12
+ read_config_file.key?(:gemfury_api_key)
13
+ end
14
+
15
+ private
16
+ def with_authorization(&block)
17
+ # Load up the credentials if user_api_key is not already set
18
+ load_credentials! if @user_api_key.nil?
19
+
20
+ # Attempt the operation and prompt user in case of
21
+ # lack of authorization or a 401 response from the server
22
+ begin
23
+ prompt_credentials! if @user_api_key.nil?
24
+ block.call
25
+ rescue Gemfury::Unauthorized
26
+ if acct = client.account
27
+ shell.say %Q(Oops! You don't have access to "#{acct}"), :red
28
+ else
29
+ shell.say "Oops! Authentication failure.", :red
30
+ @user_api_key = nil
31
+ retry
32
+ end
33
+ end
34
+ end
35
+
36
+ def prompt_credentials!
37
+ # Prompt credentials
38
+ highline = HighLine.new
39
+ highline.say 'Please enter your Gemfury credentials.'
40
+ email = highline.ask('Email: ')
41
+ passw = highline.ask('Password: ') { |q| q.echo = false }
42
+
43
+ # Request and save the API access token
44
+ if !email.empty? && !passw.empty?
45
+ @user_api_key = client.get_access_token(email, passw)
46
+ write_credentials!(email)
47
+ end
48
+ end
49
+
50
+ def load_credentials!
51
+ # Get credentials from ~/.netrc
52
+ _, @user_api_key = netrc_conf[netrc_api_host]
53
+ # Legacy loading from ~/.gem/gemfury
54
+ @user_api_key ||= read_config_file[:gemfury_api_key]
55
+ end
56
+
57
+ def write_credentials!(email)
58
+ each_netrc_host { |h| netrc_conf[h] = email, @user_api_key }
59
+ netrc_conf.save
60
+ end
61
+
62
+ def read_config_file
63
+ File.exist?(config_path) ? YAML.load_file(config_path) : {}
64
+ end
65
+
66
+ def netrc_conf
67
+ @netrc ||= Netrc.read
68
+ end
69
+
70
+ def netrc_api_host
71
+ URI.parse(client.endpoint).host
72
+ end
73
+
74
+ def each_netrc_host
75
+ [:endpoint, :gitpoint].each do |c|
76
+ yield(URI.parse(client.send(c)).host)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,72 @@
1
+ module Gemfury
2
+ # Defines constants and methods related to configuration
3
+ module Configuration
4
+ # An array of valid keys in the options hash when configuring
5
+ VALID_OPTIONS_KEYS = [
6
+ :user_api_key,
7
+ :adapter,
8
+ :endpoint,
9
+ :gitpoint,
10
+ :pushpoint,
11
+ :user_agent,
12
+ :api_version,
13
+ :account].freeze
14
+
15
+ # The adapter that will be used to connect if none is set
16
+ DEFAULT_ADAPTER = :net_http
17
+
18
+ # The endpoint that will be used to connect if none is set
19
+ DEFAULT_ENDPOINT = 'https://api.fury.io/'.freeze
20
+
21
+ # The HTTP endpoint for git repo (used for .netrc credentials)
22
+ DEFAULT_GITPOINT = 'https://git.fury.io/'.freeze
23
+
24
+ # The endpoint for the Push API if not set
25
+ DEFAULT_PUSHPOINT = 'https://push.fury.io/'.freeze
26
+
27
+ # The value sent in the 'User-Agent' header if none is set
28
+ DEFAULT_USER_AGENT = "Gemfury RubyGem #{Gemfury::VERSION}".freeze
29
+
30
+ # Default API version
31
+ DEFAULT_API_VERSION = 1
32
+
33
+ # Default user API key
34
+ DEFAULT_API_KEY = nil
35
+
36
+ # Use the current account (no impersonation)
37
+ DEFAULT_ACCOUNT = nil
38
+
39
+ # @private
40
+ attr_accessor *VALID_OPTIONS_KEYS
41
+
42
+ # When this module is extended, set all configuration options to their default values
43
+ def self.extended(base)
44
+ base.reset
45
+ end
46
+
47
+ # Convenience method to allow configuration options to be set in a block
48
+ def configure
49
+ yield self
50
+ end
51
+
52
+ # Create a hash of options and their values
53
+ def options
54
+ options = {}
55
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
56
+ options
57
+ end
58
+
59
+ # Reset all configuration options to defaults
60
+ def reset
61
+ self.user_api_key = DEFAULT_API_KEY
62
+ self.adapter = DEFAULT_ADAPTER
63
+ self.endpoint = DEFAULT_ENDPOINT
64
+ self.gitpoint = DEFAULT_GITPOINT
65
+ self.pushpoint = DEFAULT_PUSHPOINT
66
+ self.user_agent = DEFAULT_USER_AGENT
67
+ self.api_version = DEFAULT_API_VERSION
68
+ self.account = DEFAULT_ACCOUNT
69
+ self
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ module Gemfury
2
+ module Const
3
+ class << self
4
+ def host
5
+ 'www.gemfury.com'
6
+ #'localhost:3000'
7
+ end
8
+
9
+ def welcome
10
+ "Welcome to Gemfury!\nPlease complete the following information"
11
+ end
12
+
13
+ def email_error
14
+ "Invalid email address. Please try again."
15
+ end
16
+
17
+ def email_regex
18
+ return @email_regex if @email_regex
19
+ email_name_regex = '[A-Z0-9_\.%\+\-\']+'
20
+ domain_head_regex = '(?:[A-Z0-9\-]+\.)+'
21
+ domain_tld_regex = '(?:[A-Z]{2,4}|museum|travel)'
22
+ @email_regex = /^#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}$/i
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ module Gemfury
2
+ # Base Error class
3
+ Error = Class.new(StandardError)
4
+
5
+ # The Gemfury gem version doesn't match the one on the server
6
+ InvalidGemVersion = Class.new(Error)
7
+
8
+ # Client#user_api_key is not defined or Gemfury returns 401
9
+ Unauthorized = Class.new(Error)
10
+
11
+ # Client is not allowed to perform this operation
12
+ Forbidden = Class.new(Error)
13
+
14
+ # Account is locked for another operation
15
+ Conflict = Class.new(Error)
16
+
17
+ # Returned if something is not found
18
+ NotFound = Class.new(Error)
19
+
20
+ # Corrupt Gem File
21
+ CorruptGemFile = Class.new(Error)
22
+
23
+ # Version already exists
24
+ DupeVersion = Class.new(Error)
25
+
26
+ # TimeoutError for 503s
27
+ TimeoutError = Class.new(Error)
28
+ end
@@ -0,0 +1,19 @@
1
+ module Gemfury
2
+ module Platform
3
+ def home_directory
4
+ on_windows? ? ENV['USERPROFILE'] : ENV['HOME']
5
+ end
6
+
7
+ def config_path
8
+ File.expand_path('.gem/gemfury', home_directory)
9
+ end
10
+
11
+ def on_windows?
12
+ RUBY_PLATFORM =~ /mswin32|mingw32/
13
+ end
14
+
15
+ def on_mac?
16
+ RUBY_PLATFORM =~ /-darwin\d/
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ # Load Gemfury rakefile extensions
2
+ load "gemfury/tasks/release.rake"
@@ -0,0 +1,36 @@
1
+ require 'rubygems/package'
2
+ require 'gemfury'
3
+ require 'gemfury/command'
4
+
5
+ namespace 'fury' do
6
+ desc "Build gem and push it to Gemfury"
7
+ task :release, [:gemspec, :as] do |t, args|
8
+ gemspec = args[:gemspec] ||
9
+ FileList["#{Dir.pwd}/*.gemspec"][0]
10
+
11
+ if gemspec.nil? || !File.exist?(gemspec)
12
+ puts "No gemspec found"
13
+ else
14
+ puts "Building #{File.basename(gemspec)}"
15
+ spec = Gem::Specification.load(gemspec)
16
+
17
+ if Gem::Package.respond_to?(:build)
18
+ Gem::Package.build(spec)
19
+ else
20
+ require 'rubygems/builder'
21
+ Gem::Builder.new(spec).build
22
+ end
23
+
24
+ gemfile = File.basename(spec.cache_file)
25
+
26
+ params = ['push', gemfile]
27
+ params << "--as=#{args[:as]}" if args[:as]
28
+
29
+ Gemfury::Command::App.start(params)
30
+ end
31
+ end
32
+ end
33
+
34
+ namespace 'gemfury' do
35
+ task :release => 'fury:release'
36
+ end
@@ -0,0 +1,3 @@
1
+ module Gemfury
2
+ VERSION = '0.10.0.rc1'
3
+ end
@@ -0,0 +1,29 @@
1
+ require 'gemfury'
2
+ require 'gemfury/command'
3
+
4
+ class Gem::Commands::FuryCommand < Gem::Command
5
+ def description
6
+ 'Push a private gem to your Gemfury account'
7
+ end
8
+
9
+ def arguments
10
+ "GEM built gem file to push"
11
+ end
12
+
13
+ def usage
14
+ "#{program_name} GEM"
15
+ end
16
+
17
+ def initialize
18
+ super 'fury', description
19
+ add_option('-a', '--as USERNAME', 'Impersonate another account') do |value, options|
20
+ options[:as] = value
21
+ end
22
+ end
23
+
24
+ def execute
25
+ opts = options.dup
26
+ args = opts.delete(:args)
27
+ Gemfury::Command::App.send(:dispatch, "push", args, opts, {})
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ require 'rubygems/command_manager'
2
+ Gem::CommandManager.instance.register_command :fury
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gemfury
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.0.rc1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Rykov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: multi_json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.14.0
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: 1.0.0.pre
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 0.14.0
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: 1.0.0.pre
47
+ - !ruby/object:Gem::Dependency
48
+ name: netrc
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.10.0
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.12.0.pre
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.10.0
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: 0.12.0.pre
67
+ - !ruby/object:Gem::Dependency
68
+ name: faraday
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.9.0
74
+ - - "<"
75
+ - !ruby/object:Gem::Version
76
+ version: 0.16.0.pre
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.9.0
84
+ - - "<"
85
+ - !ruby/object:Gem::Version
86
+ version: 0.16.0.pre
87
+ - !ruby/object:Gem::Dependency
88
+ name: highline
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 1.6.0
94
+ - - "<"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.1.0.pre
97
+ type: :runtime
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.6.0
104
+ - - "<"
105
+ - !ruby/object:Gem::Version
106
+ version: 2.1.0.pre
107
+ description: 'Hosted repo for your public and private packages at https://gemfury.com
108
+
109
+ '
110
+ email: hello@gemfury.com
111
+ executables:
112
+ - gemfury
113
+ - fury
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - README.md
118
+ - bin/fury
119
+ - bin/gemfury
120
+ - lib/faraday/adapter/fury_http.rb
121
+ - lib/faraday/request/multipart_with_file.rb
122
+ - lib/gemfury.rb
123
+ - lib/gemfury/client.rb
124
+ - lib/gemfury/client/filters.rb
125
+ - lib/gemfury/client/middleware.rb
126
+ - lib/gemfury/command.rb
127
+ - lib/gemfury/command/app.rb
128
+ - lib/gemfury/command/authorization.rb
129
+ - lib/gemfury/configuration.rb
130
+ - lib/gemfury/const.rb
131
+ - lib/gemfury/error.rb
132
+ - lib/gemfury/platform.rb
133
+ - lib/gemfury/tasks.rb
134
+ - lib/gemfury/tasks/release.rake
135
+ - lib/gemfury/version.rb
136
+ - lib/rubygems/commands/fury_command.rb
137
+ - lib/rubygems_plugin.rb
138
+ homepage: https://gemfury.com
139
+ licenses:
140
+ - MIT
141
+ metadata: {}
142
+ post_install_message: |
143
+ ************************************************************************
144
+
145
+ Upload your first package to start using Gemfury:
146
+ fury push my-package-1.0.0.gem
147
+
148
+ If you have a directory with packages, you can use:
149
+ fury migrate ./path/to/codez
150
+
151
+ Find out what else you can do:
152
+ fury help
153
+
154
+ Follow @gemfury on Twitter for announcements, updates, and news.
155
+ https://twitter.com/gemfury
156
+
157
+ ************************************************************************
158
+ rdoc_options: []
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">"
169
+ - !ruby/object:Gem::Version
170
+ version: 1.3.1
171
+ requirements: []
172
+ rubyforge_project:
173
+ rubygems_version: 2.7.8
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: Hosted repo for your public and private packages
177
+ test_files: []