gemfury 0.12.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: fa1399aeab2f739da48ef55e4a7a6654ce9bb8527d722a9b7ce022ac082f2c2f
4
+ data.tar.gz: 176541eb909afc8610b8a4f94b3653dece97f898518a69fc137a7bd46533df25
5
+ SHA512:
6
+ metadata.gz: c69342a8284196e6e43b9a3dc3bead88cfe17b2ae098db213d5055314d703aefada6e5df8f4cd3d08a8c6a413bc27f211bd8f8be3dd802f4a8000f3c35121666
7
+ data.tar.gz: ed29f372dbec0526a614d2d8bb4ca8982ab47114a0c3d42857c4f06a480db690f7d9c898221b3be654b1e177f5d20f78382aa2069318a732b2a1ee08fb2ea71c
@@ -0,0 +1,87 @@
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
+ [![Documentation](https://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/gemfury)
8
+ [![Documentation completeness](https://inch-ci.org/github/gemfury/gemfury.svg?branch=master)](http://inch-ci.org/github/gemfury/gemfury)
9
+
10
+ This is the Gemfury CLI used to manage your Gemfury packages from the command line. If you're
11
+ familiar with the service and want to jump straight into command line action, please proceed to
12
+ the [CLI documentation](https://gemfury.com/help/gemfury-cli).
13
+
14
+ Gemfury is your personal cloud for your private and custom RubyGems, Python packages, and NPM
15
+ modules. Once you upload your packages and enable Gemfury as a source, you can securely deploy
16
+ any package to any host. It's simple, reliable, and hassle-free.
17
+
18
+
19
+ ### Introduction to Gemfury
20
+ * [Gemfury homepage](https://gemfury.com/)
21
+ * [Getting started with Gemfury](https://gemfury.com/help/getting-started)
22
+
23
+ ### Using Gemfury CLI
24
+ * [CLI documentation](https://gemfury.com/help/gemfury-cli)
25
+ * [Uploading private packages](https://gemfury.com/help/gemfury-cli#uploading-packages)
26
+ * [Manage collaborators](https://gemfury.com/help/gemfury-cli#collaboration)
27
+
28
+ ### Putting Gemfury to work
29
+ * [Install private RubyGems](https://gemfury.com/help/install-gems)
30
+ * [Install private NPM modules](https://gemfury.com/help/npm-registry)
31
+ * [Install private Python packages](https://gemfury.com/help/pypi-server)
32
+ * [Install private Composer packages](https://gemfury.com/help/php-composer-server)
33
+ * [Private RubyGems on Heroku](https://gemfury.com/help/private-gems-on-heroku)
34
+
35
+
36
+ ## Using the Gemfury Client
37
+
38
+ You can also use the client directly via Ruby; you will need a "Full access token" (API token) from `https://manage.fury.io/manage/YOUR-ACCOUNT-NAME/tokens/api`
39
+
40
+ ```ruby
41
+ require 'gemfury'
42
+
43
+ client = Gemfury::Client.new(user_api_key: "YOUR API TOKEN")
44
+
45
+ all_artifacts = client.list
46
+ puts "Available artifacts:"
47
+ puts all_artifacts
48
+
49
+ one_artifact = all_artifacts[0]
50
+ puts "Versions of the #{one_artifact['language']} artifact #{one_artifact['name']}:"
51
+ artifact_versions = client.versions(one_artifact["name"])
52
+ puts artifact_versions.map { |v| v["version"] }
53
+ ```
54
+
55
+ More information about the `Gemfury::Client` API is [hosted on rubydoc.info](https://rubydoc.info/gems/gemfury/Gemfury/Client).
56
+
57
+
58
+ ## Contribution and Improvements
59
+
60
+ 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.
61
+
62
+ ### Submitting updates
63
+
64
+ If you would like to contribute to this project, just do the following:
65
+
66
+ 1. Fork the repo on Github.
67
+ 2. Add your features and make commits to your forked repo.
68
+ 3. Make a pull request to this repo.
69
+ 4. Review will be done and changes will be requested.
70
+ 5. Once changes are done or no changes are required, pull request will be merged.
71
+ 6. The next release will have your changes in it.
72
+
73
+ Please take a look at the issues page if you want to get started.
74
+
75
+ ### Feature requests
76
+
77
+ If you think it would be nice to have a particular feature that is presently not implemented, we would love
78
+ to hear that and consider working on it. Just open an issue in Github.
79
+
80
+ ### Dependency conflicts
81
+
82
+ 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_.
83
+
84
+
85
+ ## Questions
86
+
87
+ 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,82 @@
1
+ gem "multi_json", "~> 1.10"
2
+ gem "faraday", ">= 0.9.0", "< 1.1.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
+ VALID_OPTIONS_KEYS = Configuration::CONFIGURATION_DEFAULTS.keys.freeze
27
+
28
+ class << self
29
+ # Alias for Gemfury::Client.new
30
+ #
31
+ # @return [Gemfury::Client]
32
+ def new(options={})
33
+ Gemfury::Client.new(options)
34
+ end
35
+
36
+ # Convenience method to allow configuration options to be set in a block
37
+ def configure
38
+ yield self
39
+ end
40
+
41
+ # Create a hash of options and their values
42
+ # @return [Hash] the options and their values
43
+ def options
44
+ VALID_OPTIONS_KEYS.inject({}) do |options, k|
45
+ options[k] = send(k)
46
+ options
47
+ end
48
+ end
49
+
50
+ # Reset all configuration options to defaults
51
+ # @return [Configuration] The default configuration
52
+ def reset
53
+ CONFIGURATION_DEFAULTS.each { |k, v| send("#{k}=", v) }
54
+ self
55
+ end
56
+
57
+ # Delegate to Gemfury::Client
58
+ def method_missing(method, *args, &block)
59
+ return super unless new.respond_to?(method)
60
+ new.send(method, *args, &block)
61
+ end
62
+
63
+ def respond_to?(method, include_private = false)
64
+ new.respond_to?(method, include_private) || super(method, include_private)
65
+ end
66
+
67
+ end
68
+ end
69
+
70
+ # Initialize configuration
71
+ Gemfury.reset
72
+
73
+ # Polyfill #dig for Ruby 2.2 and earlier
74
+ class Hash
75
+ unless self.instance_methods.include?(:dig)
76
+ def dig(*parts)
77
+ parts.inject(self) do |hash, part|
78
+ hash.is_a?(Hash) ? hash[part] : nil
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,273 @@
1
+ module Gemfury
2
+ class Client
3
+ include Gemfury::Client::Filters
4
+ include Gemfury::Configuration
5
+
6
+ # Creates a new API
7
+ # @param options [Hash] values for attributes described in {Gemfury::Configuration}
8
+ def initialize(options={})
9
+ options = Gemfury.options.merge(options)
10
+ Gemfury::VALID_OPTIONS_KEYS.each do |key|
11
+ send("#{key}=", options[key])
12
+ end
13
+ end
14
+
15
+ # Get the information for the current account
16
+ # @return [Hash]
17
+ def account_info
18
+ ensure_ready!(:authorization)
19
+ response = connection.get('users/me')
20
+ checked_response_body(response)
21
+ end
22
+
23
+ # Get the information for the all accounts that this account has some level of access to
24
+ # @return [Array<Hash>]
25
+ def accounts
26
+ ensure_ready!(:authorization)
27
+ response = connection.get('accounts')
28
+ checked_response_body(response)
29
+ end
30
+
31
+ # Upload an artifact file
32
+ # @param file [String] the filename to upload
33
+ # @param options [Hash] Faraday client options
34
+ # @return [Hash]
35
+ def push_gem(file, options = {})
36
+ ensure_ready!(:authorization)
37
+ push_api = connection(:url => self.pushpoint)
38
+ response = push_api.post('uploads', options.merge(:file => file))
39
+ checked_response_body(response)
40
+ end
41
+
42
+ # List available artifacts
43
+ # @param options [Hash] Faraday client options
44
+ # @return [Array<Hash>]
45
+ def list(options = {})
46
+ ensure_ready!(:authorization)
47
+ response = connection.get('gems', options)
48
+ checked_response_body(response)
49
+ end
50
+
51
+ # List versions for an artifact
52
+ # @param name [String] the name of the artifact
53
+ # @param options [Hash] Faraday client options
54
+ # @return [Array<Hash>]
55
+ def versions(name, options = {})
56
+ ensure_ready!(:authorization)
57
+ url = "gems/#{escape(name)}/versions"
58
+ response = connection.get(url, options)
59
+ checked_response_body(response)
60
+ end
61
+
62
+ # Delete an artifact version
63
+ # @param name [String] the name of the artifact
64
+ # @param version [String] the version of the artifact
65
+ # @param options [Hash] Faraday client options
66
+ # @return [Hash]
67
+ def yank_version(name, version, options = {})
68
+ ensure_ready!(:authorization)
69
+ url = "gems/#{escape(name)}/versions/#{escape(version)}"
70
+ response = connection.delete(url, options)
71
+ checked_response_body(response)
72
+ end
73
+
74
+ # LEGACY: Authentication token via email/password
75
+ def get_access_token(*args)
76
+ login(*args)['token']
77
+ end
78
+
79
+ # Get authentication info via email/password
80
+ # @param email [String] the account email address
81
+ # @param password [String] the account password
82
+ # @param opts [Hash] Faraday client options
83
+ # @return [Hash]
84
+ def login(email, password, opts = {})
85
+ ensure_ready!
86
+ opts = opts.merge(:email => email, :password => password)
87
+ checked_response_body(connection.post('login', opts))
88
+ end
89
+
90
+ # Invalidate session token
91
+ # @return [Hash]
92
+ def logout
93
+ ensure_ready!(:authorization)
94
+ response = connection.post('logout')
95
+ checked_response_body(response)
96
+ end
97
+
98
+ # List collaborators for this account
99
+ # @param options [Hash] Faraday client options
100
+ # @return [Array<Hash>]
101
+ def list_collaborators(options = {})
102
+ ensure_ready!(:authorization)
103
+ response = connection.get('collaborators', options)
104
+ checked_response_body(response)
105
+ end
106
+
107
+ # Add a collaborator to the account
108
+ # @param options [Hash] Faraday client options
109
+ # @return [Hash]
110
+ def add_collaborator(login, options = {})
111
+ ensure_ready!(:authorization)
112
+ url = "collaborators/#{escape(login)}"
113
+ response = connection.put(url, options)
114
+ checked_response_body(response)
115
+ end
116
+
117
+ # Remove a collaborator to the account
118
+ # @param login [String] the account login
119
+ # @param options [Hash] Faraday client options
120
+ # @return [Hash]
121
+ def remove_collaborator(login, options = {})
122
+ ensure_ready!(:authorization)
123
+ url = "collaborators/#{escape(login)}"
124
+ response = connection.delete(url, options)
125
+ checked_response_body(response)
126
+ end
127
+
128
+ # List Git repos for this account
129
+ # @param options [Hash] Faraday client options
130
+ # @return [Hash]
131
+ def git_repos(options = {})
132
+ ensure_ready!(:authorization)
133
+ response = connection.get(git_repo_path, options)
134
+ checked_response_body(response)
135
+ end
136
+
137
+ # Update repository name and settings
138
+ # @param repo [String] the repo name
139
+ # @param options [Hash] Faraday client options
140
+ # @return [Hash]
141
+ def git_update(repo, options = {})
142
+ ensure_ready!(:authorization)
143
+ response = connection.patch(git_repo_path(repo), options)
144
+ checked_response_body(response)
145
+ end
146
+
147
+ # Reset repository to initial state
148
+ # @param repo [String] the repo name
149
+ # @param options [Hash] Faraday client options
150
+ # @return [Hash]
151
+ def git_reset(repo, options = {})
152
+ ensure_ready!(:authorization)
153
+ response = connection.delete(git_repo_path(repo), options)
154
+ checked_response_body(response)
155
+ end
156
+
157
+ # Rebuild Git repository package
158
+ # @param repo [String] the repo name
159
+ # @param options [Hash] Faraday client options
160
+ # @return [Hash]
161
+ def git_rebuild(repo, options = {})
162
+ ensure_ready!(:authorization)
163
+ url = "#{git_repo_path(repo)}/builds"
164
+ api = connection(:api_format => :text)
165
+ checked_response_body(api.post(url, options))
166
+ end
167
+
168
+ # List Git repo's build configuration
169
+ # @param repo [String] the repo name
170
+ # @param options [Hash] Faraday client options
171
+ # @return [Hash]
172
+ def git_config(repo, options = {})
173
+ ensure_ready!(:authorization)
174
+ path = "#{git_repo_path(repo)}/config-vars"
175
+ response = connection.get(path, options)
176
+ checked_response_body(response)
177
+ end
178
+
179
+ # Update Git repo's build configuration
180
+ # @param repo [String] the repo name
181
+ # @param updates [Hash] Updates to configuration
182
+ # @param options [Hash] Faraday client options
183
+ # @return [Hash]
184
+ def git_config_update(repo, updates, options = {})
185
+ ensure_ready!(:authorization)
186
+ path = "#{git_repo_path(repo)}/config-vars"
187
+ opts = options.merge(:config_vars => updates)
188
+ response = connection.patch(path, opts)
189
+ checked_response_body(response)
190
+ end
191
+
192
+ private
193
+ def escape(str)
194
+ CGI.escape(str)
195
+ end
196
+
197
+ def git_repo_path(*args)
198
+ rest = args.map { |a| escape(a) }
199
+ ['git/repos', self.account || 'me'].concat(rest).join('/')
200
+ end
201
+
202
+ def connection(options = {})
203
+ # The 'Accept' HTTP header for API versioning
204
+ http_accept = begin
205
+ v = options.delete(:api_version) || self.api_version
206
+ f = options.delete(:api_format) || :json
207
+ "application/vnd.fury.v#{v.to_i}+#{f}"
208
+ end
209
+
210
+ # Faraday client options
211
+ options = {
212
+ :url => self.endpoint,
213
+ :params => {},
214
+ :headers => {
215
+ :accept => http_accept,
216
+ :user_agent => self.user_agent,
217
+ :x_gem_version => Gemfury::VERSION,
218
+ }.merge(options.delete(:headers) || {})
219
+ }.merge(options)
220
+
221
+ if self.user_api_key
222
+ options[:headers][:authorization] = self.user_api_key
223
+ end
224
+
225
+ if self.account
226
+ options[:params][:as] = self.account
227
+ end
228
+
229
+ Faraday.new(options) do |builder|
230
+ builder.use Faraday::Request::MultipartWithFile
231
+ builder.use Faraday::Request::Multipart
232
+ builder.use Faraday::Request::UrlEncoded
233
+ builder.use ParseJson
234
+ builder.use Handle503
235
+ builder.adapter :fury_http
236
+ end
237
+ end
238
+
239
+ def checked_response_body(response)
240
+ if response.success?
241
+ return response.body
242
+ else
243
+ error = (response.body || {})['error'] || {}
244
+ error_class = case error['type']
245
+ when 'Forbidden' then Gemfury::Forbidden
246
+ when 'GemVersionError' then Gemfury::InvalidGemVersion
247
+ when 'InvalidGemFile' then Gemfury::CorruptGemFile
248
+ when 'DupeVersion' then Gemfury::DupeVersion
249
+ else
250
+ case response.status
251
+ when 401 then Gemfury::Unauthorized
252
+ when 403 then Gemfury::Forbidden
253
+ when 404 then Gemfury::NotFound
254
+ when 409 then Gemfury::Conflict
255
+ when 503 then Gemfury::TimeoutError
256
+ else Gemfury::Error
257
+ end
258
+ end
259
+
260
+ raise(error_class, error['message'])
261
+ end
262
+ end
263
+
264
+ def s3_put_file(uri, file)
265
+ Faraday::Connection.new(uri) do |f|
266
+ f.adapter :net_http
267
+ end.put(uri, file, {
268
+ :content_length => file.stat.size.to_s,
269
+ :content_type => ''
270
+ })
271
+ end
272
+ end
273
+ end