diffend 0.2.19 → 0.2.23

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f18edf14b16e7f2ec3ce0c574ade976e78e3eac84f8395e45fc53595a8e3f91
4
- data.tar.gz: 292e755dac0d191787b77fb8556b5e2f90f9e040ee9e28486de90601b2c2a67c
3
+ metadata.gz: 5ce266f8f72de49360adc1e6e1f79c8bf5fa08727ffc990292877c015e1040ee
4
+ data.tar.gz: 1a71a4a519b1f2afb9bc993726c045b4db5b87833459ba8f7192c2a2f4232aa6
5
5
  SHA512:
6
- metadata.gz: 73326da64425debc8c27ad1dd216df34313a45795a2c6f555d0e5df067dfc17977ae9ee6e8307ab1df33af58a87ca23511ed3920eaa9c0bcec566fef602c30c3
7
- data.tar.gz: eabf666e6c1ef7a08afaadf519011edac2416f0a2fa13152a9112b898b94dde1f598f23866a9823220be308aa091d9dab6b6d03e95191f3d22ba43509d3933fa
6
+ metadata.gz: '08dd6da1d3984200d9ac07fd9fd1f9a0adf6b7746f86a77ab560b77b356dc6fad819513adea6fe2d714b1f06ed8cf5441d796681fd507b64247a2db3560d3138'
7
+ data.tar.gz: 2155bbba6da089606b38d36fcec4259054f6cac053bf56eefb303d6d3aa223ba4253ca771249a2543696c636e8c509aa75ceb3ab50f055dd18a2ba9715e5cb9f
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -9,6 +9,9 @@ jobs:
9
9
  matrix:
10
10
  ruby:
11
11
  - '2.7'
12
+ - '2.6'
13
+ - '2.5'
14
+ - 'jruby'
12
15
  include:
13
16
  - ruby: '2.7'
14
17
  coverage: 'true'
data/CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
1
  # Changelog
2
2
 
3
3
  ## [Unreleased][master]
4
+ - fix how we build gem platform ([#26](https://github.com/diffend-io/diffend-ruby/pull/26))
5
+ - test against jruby, ruby-2.5 and ruby-2.6 ([#25](https://github.com/diffend-io/diffend-ruby/pull/25))
6
+
7
+ ## [0.2.22] (2020-09-03)
8
+ - fix how we build host command
9
+
10
+ ## [0.2.21] (2020-09-03)
11
+ - bring back support for ruby 2.5.x
12
+
13
+ ## [0.2.20] (2020-09-03)
14
+ - expose host command ([#21](https://github.com/diffend-io/diffend-ruby/pull/21))
15
+ - expose host pid ([#20](https://github.com/diffend-io/diffend-ruby/pull/20))
16
+ - use `Bundler.feature_flag.default_cli_command` which is used as the default task if no command provided, instead of `Diffend::Commands::INSTALL` ([#19](https://github.com/diffend-io/diffend-ruby/pull/19))
17
+ - better error handling ([#18](https://github.com/diffend-io/diffend-ruby/pull/18))
18
+ - better detection of gem versions ([#17](https://github.com/diffend-io/diffend-ruby/pull/17))
19
+ - introduce `Diffend::BuildBundlerDefinition` ([#16](https://github.com/diffend-io/diffend-ruby/pull/16))
4
20
 
5
21
  ## [0.2.19] (2020-08-18)
6
22
 
@@ -22,7 +38,10 @@
22
38
 
23
39
  - initial release
24
40
 
25
- [master]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.19...HEAD
41
+ [master]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.22...HEAD
42
+ [0.2.22]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.21...v0.2.22
43
+ [0.2.21]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.20...v0.2.21
44
+ [0.2.20]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.19...v0.2.20
26
45
  [0.2.19]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.18...v0.2.19
27
46
  [0.2.18]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.17...v0.2.18
28
47
  [0.2.17]: https://github.com/diffend-io/diffend-ruby/compare/v0.2.16...v0.2.17
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ plugin 'diffend'
7
7
  gemspec
8
8
 
9
9
  group :development, :test do
10
- gem 'byebug'
10
+ gem 'byebug', platform: :ruby
11
+ gem 'pry', platform: :jruby
11
12
  gem 'rspec'
12
13
  end
data/Gemfile.lock CHANGED
@@ -1,13 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- diffend (0.2.19)
4
+ diffend (0.2.23)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  byebug (11.1.3)
10
+ coderay (1.1.3)
10
11
  diff-lcs (1.4.4)
12
+ ffi (1.13.1-java)
13
+ method_source (1.0.0)
14
+ pry (0.13.1-java)
15
+ coderay (~> 1.1)
16
+ method_source (~> 1.0)
17
+ spoon (~> 0.0)
11
18
  rake (13.0.1)
12
19
  rspec (3.9.0)
13
20
  rspec-core (~> 3.9.0)
@@ -22,14 +29,18 @@ GEM
22
29
  diff-lcs (>= 1.2.0, < 2.0)
23
30
  rspec-support (~> 3.9.0)
24
31
  rspec-support (3.9.3)
32
+ spoon (0.0.6)
33
+ ffi
25
34
 
26
35
  PLATFORMS
36
+ java
27
37
  ruby
28
38
 
29
39
  DEPENDENCIES
30
40
  bundler
31
41
  byebug
32
42
  diffend!
43
+ pry
33
44
  rake
34
45
  rspec
35
46
 
data/lib/diffend.rb CHANGED
@@ -5,16 +5,21 @@
5
5
  ].each(&method(:require))
6
6
 
7
7
  %w[
8
+ build_bundler_definition
8
9
  errors
9
10
  config/fetcher
10
11
  config/file_finder
11
12
  config/validator
12
13
  commands
14
+ handle_errors/messages
15
+ handle_errors/build_exception_payload
16
+ handle_errors/display_to_stdout
17
+ handle_errors/report
18
+ request
13
19
  voting
14
20
  ].each { |file| require "diffend/#{file}" }
15
21
 
16
22
  %w[
17
- request
18
23
  versions/local
19
24
  versions/remote
20
25
  ].each { |file| require "diffend/voting/#{file}" }
@@ -22,7 +27,7 @@
22
27
  # Diffend main namespace
23
28
  module Diffend
24
29
  # Current plugin version
25
- VERSION = '0.2.19'
30
+ VERSION = '0.2.23'
26
31
  # Diffend homepage
27
32
  HOMEPAGE = 'https://diffend.io'
28
33
 
@@ -30,27 +35,28 @@ module Diffend
30
35
  # Registers the plugin and add before install all hook
31
36
  def register
32
37
  Bundler::Plugin.add_hook('before-install-all') do |_|
33
- Diffend::Voting.call(
34
- command,
35
- build_definition(command)
36
- )
38
+ execute
37
39
  end
38
40
  end
39
41
 
40
- # Build clean instance of bundler definition, as we don't want to pollute the main one
41
- #
42
- # @param command [String] bundler command that we are executing
43
- #
44
- # @return [Bundler::Definition]
45
- def build_definition(command)
46
- unlock = command == 'update' ? true : nil
42
+ # Execute diffend plugin
43
+ def execute
44
+ config = fetch_config
47
45
 
48
- Bundler.configure
49
-
50
- Bundler::Definition.build(
51
- Bundler.default_gemfile,
52
- Bundler.default_lockfile,
53
- unlock
46
+ Diffend::Voting.call(
47
+ command,
48
+ Diffend::BuildBundlerDefinition.call(
49
+ command,
50
+ Bundler.default_gemfile,
51
+ Bundler.default_lockfile
52
+ )
53
+ )
54
+ rescue StandardError => e
55
+ Diffend::HandleErrors::Report.call(
56
+ exception: e,
57
+ config: config,
58
+ message: :unhandled_exception,
59
+ report: true
54
60
  )
55
61
  end
56
62
 
@@ -58,7 +64,18 @@ module Diffend
58
64
  #
59
65
  # @return [String]
60
66
  def command
61
- ARGV.first || Diffend::Commands::INSTALL
67
+ ARGV.first || Bundler.feature_flag.default_cli_command.to_s
68
+ end
69
+
70
+ # Fetch diffend config file
71
+ #
72
+ # @return [OpenStruct, nil] configuration object
73
+ #
74
+ # @raise [Errors::MissingConfigurationFile] when no config file
75
+ def fetch_config
76
+ Config::Fetcher.call(
77
+ File.expand_path('..', Bundler.bin_path)
78
+ )
62
79
  end
63
80
  end
64
81
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Builds bundler definition used within the plugin
5
+ module BuildBundlerDefinition
6
+ class << self
7
+ # Build clean instance of bundler definition, as we don't want to pollute the main one
8
+ #
9
+ # @param command [String] bundler command that we are executing
10
+ # @param gemfile [String] path to Gemfile
11
+ # @param lockfile [String] path to Gemfile.lock
12
+ #
13
+ # @return [Bundler::Definition]
14
+ def call(command, gemfile, lockfile)
15
+ unlock = command == 'update' ? true : nil
16
+
17
+ Bundler.configure
18
+ Bundler::Fetcher.disable_endpoint = nil
19
+
20
+ Bundler::Definition
21
+ .build(gemfile, lockfile, unlock)
22
+ .tap(&:validate_runtime!)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Diffend
6
+ module HandleErrors
7
+ # Module responsible for building exception payload
8
+ module BuildExceptionPayload
9
+ class << self
10
+ # Build exception payload
11
+ #
12
+ # @param exception [Exception] expection that was raised
13
+ # @param payload [Hash] with versions to check
14
+ #
15
+ # @return [Hash]
16
+ def call(exception, payload)
17
+ {
18
+ request_id: SecureRandom.uuid,
19
+ payload: payload,
20
+ exception: {
21
+ class: exception.class,
22
+ message: exception.message,
23
+ backtrace: exception.backtrace
24
+ }
25
+ }.freeze
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ module HandleErrors
5
+ # Module responsible for displaying exception payload to stdout
6
+ module DisplayToStdout
7
+ class << self
8
+ # Display exception payload to stdout
9
+ #
10
+ # @param exception_payload [Hash]
11
+ def call(exception_payload)
12
+ puts exception_payload.to_json
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ module HandleErrors
5
+ module Messages
6
+ PAYLOAD_DUMP = '^^^ Above is the dump of your request ^^^'
7
+ UNHANDLED_EXCEPTION = <<~MSG
8
+ \nSomething went really wrong. We recorded this incident in our system and will review it.\n
9
+ This is a bug, don't hesitate.\n
10
+ Create an issue at https://github.com/diffend-io/diffend-ruby/issues\n
11
+ MSG
12
+ REQUEST_ERROR = <<~MSG
13
+ \nWe were unable to process your request at this time. We recorded this incident in our system and will review it.\n
14
+ If you think that this is a bug, don't hesitate.\n
15
+ Create an issue at https://github.com/diffend-io/diffend-ruby/issues\n
16
+ MSG
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ module HandleErrors
5
+ # Module responsible for reporting errors to diffend
6
+ module Report
7
+ class << self
8
+ # Execute request to Diffend
9
+ #
10
+ # @param exception [Exception] expection that was raised
11
+ # @param payload [Hash] with versions to check
12
+ # @param config [OpenStruct] Diffend config
13
+ # @param message [Symbol] message that we want to display
14
+ # @param report [Boolean] if true we will report the issue to diffend
15
+ #
16
+ # @return [Net::HTTPResponse] response from Diffend
17
+ def call(exception:, payload: {}, config:, message:, report: false)
18
+ exception_payload = prepare_exception_payload(exception, payload)
19
+
20
+ Bundler.ui.error(Diffend::HandleErrors::Messages::PAYLOAD_DUMP)
21
+ Bundler.ui.error(Diffend::HandleErrors::Messages.const_get(message.to_s.upcase))
22
+
23
+ if report
24
+ Diffend::Request.call(
25
+ config,
26
+ errors_url(config.project_id),
27
+ exception_payload
28
+ )
29
+ end
30
+
31
+ exit 1
32
+ end
33
+
34
+ # Prepare exception payload and display it to stdout
35
+ #
36
+ # @param exception [Exception] expection that was raised
37
+ # @param payload [Hash] with versions to check
38
+ #
39
+ # @return [Hash]
40
+ def prepare_exception_payload(exception, payload)
41
+ Diffend::HandleErrors::BuildExceptionPayload
42
+ .call(exception, payload)
43
+ .tap(&Diffend::HandleErrors::DisplayToStdout.method(:call))
44
+ end
45
+
46
+ # Provides diffend errors endpoint url
47
+ #
48
+ # @param project_id [String] diffend project_id
49
+ #
50
+ # @return [String] diffend endpoint
51
+ def errors_url(project_id)
52
+ return ENV['DIFFEND_ERROR_URL'] if ENV.key?('DIFFEND_ERROR_URL')
53
+
54
+ "https://my.diffend.io/api/projects/#{project_id}/errors"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'openssl'
5
+ require 'json'
6
+
7
+ module Diffend
8
+ # Module responsible for doing request to Diffend
9
+ module Request
10
+ # Message displayed when connection issue occured and we will retry
11
+ CONNECTION_MESSAGE = 'We experienced a connection issue, retrying...'
12
+ # List of connection exceptions
13
+ CONNECTION_EXCEPTIONS = [
14
+ Errno::ECONNRESET,
15
+ Errno::ENETUNREACH,
16
+ Errno::EHOSTUNREACH,
17
+ Errno::ECONNREFUSED
18
+ ].freeze
19
+ # Message displayed when timeout occured and we will retry
20
+ TIMEOUT_MESSAGE = 'We experienced a connection issue, retrying...'
21
+ # List of timeout exceptions
22
+ TIMEOUT_EXCEPTIONS = [
23
+ Net::OpenTimeout,
24
+ Net::ReadTimeout
25
+ ].freeze
26
+ # Number of retries
27
+ RETRIES = 3
28
+ # Request headers
29
+ HEADERS = { 'Content-Type': 'application/json' }.freeze
30
+
31
+ private_constant :HEADERS
32
+
33
+ class << self
34
+ # Execute request
35
+ #
36
+ # @param config [OpenStruct] diffend config
37
+ # @param endpoint_url [String]
38
+ # @param payload [Hash]
39
+ #
40
+ # @return [Net::HTTPResponse] response from Diffend
41
+ def call(config, endpoint_url, payload)
42
+ retry_count ||= -1
43
+
44
+ build_http(endpoint_url) do |http, uri|
45
+ http.request(build_request(uri, config, payload))
46
+ end
47
+ rescue *CONNECTION_EXCEPTIONS => e
48
+ retry_count += 1
49
+
50
+ retry if handle_retry(CONNECTION_MESSAGE, retry_count)
51
+
52
+ Diffend::HandleErrors::Report.call(
53
+ exception: e,
54
+ payload: payload,
55
+ config: config,
56
+ message: :request_error
57
+ )
58
+ rescue *TIMEOUT_EXCEPTIONS => e
59
+ retry_count += 1
60
+
61
+ retry if handle_retry(TIMEOUT_MESSAGE, retry_count)
62
+
63
+ Diffend::HandleErrors::Report.call(
64
+ exception: e,
65
+ payload: payload,
66
+ config: config,
67
+ message: :request_error
68
+ )
69
+ end
70
+
71
+ # Handle retry
72
+ #
73
+ # @param message [String] message we want to display
74
+ # @param retry_count [Integer]
75
+ def handle_retry(message, retry_count)
76
+ return false if retry_count == RETRIES
77
+
78
+ Bundler.ui.error(message)
79
+ sleep(exponential_backoff(retry_count))
80
+
81
+ retry_count < RETRIES
82
+ end
83
+
84
+ # Builds http connection object
85
+ #
86
+ # @param url [String] command endpoint url
87
+ def build_http(url)
88
+ uri = URI(url)
89
+
90
+ Net::HTTP.start(
91
+ uri.host,
92
+ uri.port,
93
+ use_ssl: uri.scheme == 'https',
94
+ verify_mode: OpenSSL::SSL::VERIFY_NONE,
95
+ open_timeout: 5,
96
+ read_timeout: 5
97
+ ) { |http| yield(http, uri) }
98
+ end
99
+
100
+ # Build http post request and assigns headers and payload
101
+ #
102
+ # @param uri [URI::HTTPS]
103
+ # @param config [OpenStruct] Diffend config
104
+ # @param payload [Hash] with versions to check
105
+ #
106
+ # @return [Net::HTTP::Post]
107
+ def build_request(uri, config, payload)
108
+ Net::HTTP::Post
109
+ .new(uri.request_uri, HEADERS)
110
+ .tap { |request| assign_auth(request, config) }
111
+ .tap { |request| assign_payload(request, payload) }
112
+ end
113
+
114
+ # Assigns basic authorization if provided in the config
115
+ #
116
+ # @param request [Net::HTTP::Post] prepared http post
117
+ # @param config [OpenStruct] Diffend config
118
+ def assign_auth(request, config)
119
+ return unless config
120
+ return unless config.shareable_id
121
+ return unless config.shareable_key
122
+
123
+ request.basic_auth(config.shareable_id, config.shareable_key)
124
+ end
125
+
126
+ # Assigns payload as json
127
+ #
128
+ # @param request [Net::HTTP::Post] prepared http post
129
+ # @param payload [Hash] with versions to check
130
+ def assign_payload(request, payload)
131
+ request.body = JSON.dump(payload: payload)
132
+ end
133
+
134
+ def exponential_backoff(retry_count)
135
+ 2**(retry_count + 1)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -65,18 +65,16 @@ module Diffend
65
65
  def build_install
66
66
  hash = build_main
67
67
 
68
- @definition.requested_specs.each do |spec|
68
+ @definition.specs.each do |spec|
69
69
  next if skip?(spec.source)
70
70
 
71
71
  locked_spec = @locked_specs.find { |s| s.name == spec.name }
72
72
 
73
- spec2 = locked_spec || spec
74
-
75
- hash['dependencies'][spec2.name] = {
76
- 'platform' => build_spec_platform(spec2),
77
- 'source' => build_spec_source(spec2),
78
- 'type' => build_dependency_type(spec2.name),
79
- 'versions' => build_versions(spec2)
73
+ hash['dependencies'][spec.name] = {
74
+ 'platform' => build_spec_platform(spec, locked_spec),
75
+ 'source' => build_spec_source(spec),
76
+ 'type' => build_dependency_type(spec.name),
77
+ 'versions' => build_versions(spec, locked_spec)
80
78
  }
81
79
  end
82
80
 
@@ -89,13 +87,13 @@ module Diffend
89
87
  def build_update
90
88
  hash = build_main
91
89
 
92
- @definition.requested_specs.each do |spec|
90
+ @definition.specs.each do |spec|
93
91
  next if skip?(spec.source)
94
92
 
95
93
  locked_spec = @locked_specs.find { |s| s.name == spec.name }
96
94
 
97
95
  hash['dependencies'][spec.name] = {
98
- 'platform' => build_spec_platform(spec),
96
+ 'platform' => build_spec_platform(spec, locked_spec),
99
97
  'source' => build_spec_source(spec),
100
98
  'type' => build_dependency_type(spec.name),
101
99
  'versions' => build_versions(spec, locked_spec)
@@ -126,7 +124,11 @@ module Diffend
126
124
  #
127
125
  # @return [Array<String>]
128
126
  def build_versions(spec, locked_spec = nil)
129
- locked_spec ? [locked_spec.version.to_s, spec.version.to_s] : [spec.version.to_s]
127
+ if locked_spec && locked_spec.version.to_s != spec.version.to_s
128
+ [locked_spec.version.to_s, spec.version.to_s]
129
+ else
130
+ [spec.version.to_s]
131
+ end
130
132
  end
131
133
 
132
134
  # @param specs [Array] specs that are direct dependencies
@@ -144,10 +146,25 @@ module Diffend
144
146
  # Build gem platform
145
147
  #
146
148
  # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
149
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
147
150
  #
148
151
  # @return [String]
149
- def build_spec_platform(spec)
150
- spec.platform || spec.send(:generic_local_platform)
152
+ def build_spec_platform(spec, locked_spec)
153
+ spec.platform || locked_spec&.platform || build_spec_generic_platform(spec)
154
+ end
155
+
156
+ # Build gem generic platform
157
+ #
158
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
159
+ #
160
+ # @return [String]
161
+ def build_spec_generic_platform(spec)
162
+ platform = spec.send(:generic_local_platform)
163
+
164
+ case platform
165
+ when String then platform
166
+ when Gem::Platform then platform.os
167
+ end
151
168
  end
152
169
 
153
170
  # Build gem source type
@@ -229,17 +246,17 @@ module Diffend
229
246
  # @return [Array<Hash>]
230
247
  def build_sources
231
248
  sources = @definition.send(:sources).rubygems_sources
232
- hash = []
249
+ hash = {}
233
250
 
234
251
  sources.each do |source|
235
252
  type = build_source_type(source.remotes)
236
253
 
237
254
  source.remotes.each do |src|
238
- hash << { 'name' => source_name(src), 'type' => type }
255
+ hash[source_name(src)] = type
239
256
  end
240
257
  end
241
258
 
242
- hash
259
+ hash.map { |name, type| { 'name' => name, 'type' => type } }
243
260
  end
244
261
 
245
262
  # Build gem source type
@@ -23,11 +23,23 @@ module Diffend
23
23
  def call(command, definition)
24
24
  config = fetch_config
25
25
 
26
- response = Request.call(
27
- command, payload(command, config&.project_id, definition), config
26
+ payload = payload(command, config.project_id, definition)
27
+
28
+ response = Diffend::Request.call(
29
+ config,
30
+ commands_url(command, config.project_id),
31
+ payload
28
32
  )
29
33
 
30
34
  JSON.parse(response.body)
35
+ rescue StandardError => e
36
+ Diffend::HandleErrors::Report.call(
37
+ exception: e,
38
+ payload: payload,
39
+ config: config,
40
+ message: :unhandled_exception,
41
+ report: true
42
+ )
31
43
  end
32
44
 
33
45
  # Build diffend, host, packages, and platform specific information
@@ -85,6 +97,9 @@ module Diffend
85
97
  }.freeze
86
98
  end
87
99
 
100
+ # Build platform ruby information
101
+ #
102
+ # @return [Hash]
88
103
  def build_platform_ruby
89
104
  if defined?(JRUBY_VERSION)
90
105
  revision = JRUBY_REVISION.to_s
@@ -117,7 +132,7 @@ module Diffend
117
132
  uname = Etc.uname
118
133
 
119
134
  {
120
- 'command' => { 'name' => '', 'options' => '' },
135
+ 'command' => build_host_command,
121
136
  'ips' => build_host_ips,
122
137
  'name' => uname[:nodename],
123
138
  'system' => {
@@ -127,10 +142,24 @@ module Diffend
127
142
  'version' => uname[:version]
128
143
  },
129
144
  'tags' => build_host_tags,
130
- 'user' => Etc.getpwuid(Process.uid).name
145
+ 'user' => Etc.getpwuid(Process.uid).name,
146
+ 'pid' => Process.pid
131
147
  }.freeze
132
148
  end
133
149
 
150
+ # Build host command information
151
+ #
152
+ # @return [Hash]
153
+ def build_host_command
154
+ {
155
+ 'name' => $PROGRAM_NAME.split('/').last.strip,
156
+ 'options' => ARGV.join(' ')
157
+ }
158
+ end
159
+
160
+ # Build host ips, except localhost and loopback
161
+ #
162
+ # @return [Array<String>]
134
163
  def build_host_ips
135
164
  Socket.ip_address_list.map do |ip|
136
165
  next if ip.ipv4_loopback? || ip.ipv6_loopback? || ip.ipv6_linklocal?
@@ -139,6 +168,9 @@ module Diffend
139
168
  end.compact
140
169
  end
141
170
 
171
+ # Build host tags
172
+ #
173
+ # @return [Array]
142
174
  def build_host_tags
143
175
  tags = []
144
176
 
@@ -155,7 +187,7 @@ module Diffend
155
187
  tags
156
188
  end
157
189
 
158
- # Fetch coditsu config file
190
+ # Fetch diffend config file
159
191
  #
160
192
  # @return [OpenStruct, nil] configuration object
161
193
  #
@@ -165,6 +197,18 @@ module Diffend
165
197
  File.expand_path('..', Bundler.bin_path)
166
198
  )
167
199
  end
200
+
201
+ # Provides diffend command endpoint url
202
+ #
203
+ # @param command [String] either install or update
204
+ # @param project_id [String] diffend project_id
205
+ #
206
+ # @return [String] diffend endpoint
207
+ def commands_url(command, project_id)
208
+ return ENV['DIFFEND_COMMAND_URL'] if ENV.key?('DIFFEND_COMMAND_URL')
209
+
210
+ "https://my.diffend.io/api/projects/#{project_id}/bundle/#{command}"
211
+ end
168
212
  end
169
213
  end
170
214
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diffend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19
4
+ version: 0.2.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomasz Pajor
@@ -34,7 +34,7 @@ cert_chain:
34
34
  9MmF6uCQa1EjK2p8tYT0MnbHrFkoehxdX4VO9y99GAkhZyJNKPYPtyAUFV27sT2V
35
35
  LfCJRk4ifKIN/FUCwDSn8Cz0m6oH265q0p6wdzI6qrWOjP8tGOMBTA==
36
36
  -----END CERTIFICATE-----
37
- date: 2020-08-18 00:00:00.000000000 Z
37
+ date: 2020-09-06 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: bundler
@@ -92,13 +92,18 @@ files:
92
92
  - certs/tomaszpajor.pem
93
93
  - diffend.gemspec
94
94
  - lib/diffend.rb
95
+ - lib/diffend/build_bundler_definition.rb
95
96
  - lib/diffend/commands.rb
96
97
  - lib/diffend/config/fetcher.rb
97
98
  - lib/diffend/config/file_finder.rb
98
99
  - lib/diffend/config/validator.rb
99
100
  - lib/diffend/errors.rb
101
+ - lib/diffend/handle_errors/build_exception_payload.rb
102
+ - lib/diffend/handle_errors/display_to_stdout.rb
103
+ - lib/diffend/handle_errors/messages.rb
104
+ - lib/diffend/handle_errors/report.rb
105
+ - lib/diffend/request.rb
100
106
  - lib/diffend/voting.rb
101
- - lib/diffend/voting/request.rb
102
107
  - lib/diffend/voting/versions/local.rb
103
108
  - lib/diffend/voting/versions/remote.rb
104
109
  - plugins.rb
metadata.gz.sig CHANGED
Binary file
@@ -1,191 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'net/http'
4
- require 'openssl'
5
- require 'json'
6
- require 'securerandom'
7
-
8
- module Diffend
9
- module Voting
10
- # Module responsible for doing request to Diffend
11
- module Request
12
- # List of connection exceptions
13
- CONNECTION_EXCEPTIONS = [
14
- Errno::ECONNRESET,
15
- Errno::ENETUNREACH,
16
- Errno::EHOSTUNREACH,
17
- Errno::ECONNREFUSED
18
- ].freeze
19
- # List of timeout exceptions
20
- TIMEOUT_EXCEPTIONS = [
21
- Net::OpenTimeout,
22
- Net::ReadTimeout
23
- ].freeze
24
- # Request headers
25
- HEADERS = { 'Content-Type': 'application/json' }.freeze
26
-
27
- private_constant :HEADERS
28
-
29
- class << self
30
- # Execute request to Diffend
31
- #
32
- # @param command [String] either install or update
33
- # @param payload [Hash] with versions to check
34
- # @param config [OpenStruct] Diffend config
35
- #
36
- # @return [Net::HTTPResponse] response from Diffend
37
- def call(command, payload, config)
38
- retry_count ||= 0
39
-
40
- build_http(commands_url(command, config.project_id)) do |http, uri|
41
- http.request(build_request(uri, config, payload))
42
- end
43
- rescue *CONNECTION_EXCEPTIONS => e
44
- Bundler.ui.error('We experienced a connection issue, retrying...')
45
- sleep(exponential_backoff(retry_count))
46
- retry_count += 1
47
-
48
- retry if retry_count < 3
49
-
50
- output_report(build_report(payload, e))
51
- Bundler.ui.error('^^^ Above is the dump of your request ^^^')
52
- Bundler.ui.error(build_request_error_message)
53
-
54
- exit 1
55
- rescue *TIMEOUT_EXCEPTIONS => e
56
- Bundler.ui.error('We experienced a timeout issue, retrying...')
57
- sleep(exponential_backoff(retry_count))
58
- retry_count += 1
59
-
60
- retry if retry_count < 3
61
-
62
- output_report(build_report(payload, e))
63
- Bundler.ui.error('^^^ Above is the dump of your request ^^^')
64
- Bundler.ui.error(build_request_error_message)
65
-
66
- exit 1
67
- rescue StandardError => e
68
- exception_payload = build_report(payload, e)
69
- output_report(exception_payload)
70
- Bundler.ui.error('^^^ Above is the dump of your request ^^^')
71
- Bundler.ui.error(build_unhandled_exception_message)
72
-
73
- build_http(errors_url(config.project_id)) do |http, uri|
74
- http.request(build_request(uri, config, exception_payload))
75
- end
76
-
77
- exit 1
78
- end
79
-
80
- # Builds http connection object
81
- #
82
- # @param url [String] command endpoint url
83
- def build_http(url)
84
- uri = URI(url)
85
-
86
- Net::HTTP.start(
87
- uri.host,
88
- uri.port,
89
- use_ssl: uri.scheme == 'https',
90
- verify_mode: OpenSSL::SSL::VERIFY_NONE,
91
- open_timeout: 5,
92
- read_timeout: 5
93
- ) { |http| yield(http, uri) }
94
- end
95
-
96
- # Build http post request and assigns headers and payload
97
- #
98
- # @param uri [URI::HTTPS]
99
- # @param config [OpenStruct] Diffend config
100
- # @param payload [Hash] with versions to check
101
- #
102
- # @return [Net::HTTP::Post]
103
- def build_request(uri, config, payload)
104
- Net::HTTP::Post
105
- .new(uri.request_uri, HEADERS)
106
- .tap { |request| assign_auth(request, config) }
107
- .tap { |request| assign_payload(request, payload) }
108
- end
109
-
110
- # Assigns basic authorization if provided in the config
111
- #
112
- # @param request [Net::HTTP::Post] prepared http post
113
- # @param config [OpenStruct] Diffend config
114
- def assign_auth(request, config)
115
- return unless config
116
- return unless config.shareable_id
117
- return unless config.shareable_key
118
-
119
- request.basic_auth(config.shareable_id, config.shareable_key)
120
- end
121
-
122
- # Assigns payload as json
123
- #
124
- # @param request [Net::HTTP::Post] prepared http post
125
- # @param payload [Hash] with versions to check
126
- def assign_payload(request, payload)
127
- request.body = JSON.dump(payload: payload)
128
- end
129
-
130
- # Provides diffend command endpoint url
131
- #
132
- # @param command [String] either install or update
133
- # @param project_id [String] diffend project_id
134
- #
135
- # @return [String] diffend endpoint
136
- def commands_url(command, project_id)
137
- return ENV['DIFFEND_COMMAND_URL'] if ENV.key?('DIFFEND_COMMAND_URL')
138
-
139
- "https://my.diffend.io/api/projects/#{project_id}/bundle/#{command}"
140
- end
141
-
142
- # Provides diffend errors endpoint url
143
- #
144
- # @param project_id [String] diffend project_id
145
- #
146
- # @return [String] diffend endpoint
147
- def errors_url(project_id)
148
- return ENV['DIFFEND_ERROR_URL'] if ENV.key?('DIFFEND_ERROR_URL')
149
-
150
- "https://my.diffend.io/api/projects/#{project_id}/errors"
151
- end
152
-
153
- def exponential_backoff(retry_count)
154
- 2**(retry_count + 1)
155
- end
156
-
157
- def build_request_error_message
158
- <<~MSG
159
- \nWe were unable to process your request at this time. We recorded this incident in our system and will review it.\n
160
- If you think that this is a bug, don't hesitate.\n
161
- Create an issue on https://github.com/diffend-io/diffend-ruby/issues\n
162
- MSG
163
- end
164
-
165
- def build_unhandled_exception_message
166
- <<~MSG
167
- \nSomething went really wrong. We recorded this incident in our system and will review it.\n
168
- This is a bug, don't hesitate.\n
169
- Create an issue on https://github.com/diffend-io/diffend-ruby/issues\n
170
- MSG
171
- end
172
-
173
- def build_report(payload, exception)
174
- {
175
- request_id: SecureRandom.uuid,
176
- payload: payload,
177
- exception: {
178
- class: exception.class,
179
- message: exception.message,
180
- backtrace: exception.backtrace
181
- }
182
- }
183
- end
184
-
185
- def output_report(report)
186
- puts report.to_json
187
- end
188
- end
189
- end
190
- end
191
- end