gemfury 0.12.0.rc1

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.
@@ -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