diffend-monitor 0.2.28 → 0.2.34

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,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building packages information from local context
7
+ class Packages
8
+ # Definition of a local path, if it matches it means that we are the source
9
+ ME_PATH = '.'
10
+ # Sources that we expect to match ourselves too
11
+ ME_SOURCES = [
12
+ Bundler::Source::Gemspec,
13
+ Bundler::Source::Path
14
+ ].freeze
15
+ # List of dependency types
16
+ DEPENDENCIES_TYPES = {
17
+ direct: 0,
18
+ dependency: 1
19
+ }.freeze
20
+ # List of sources types
21
+ SOURCES_TYPES = {
22
+ valid: 0,
23
+ multiple_primary: 1
24
+ }.freeze
25
+ # List of gem sources types
26
+ GEM_SOURCES_TYPES = {
27
+ local: 0,
28
+ gemfile_source: 1,
29
+ gemfile_git: 2,
30
+ gemfile_path: 3
31
+ }.freeze
32
+
33
+ class << self
34
+ # @param command [String] command executed via bundler
35
+ # @param definition [Bundler::Definition] definition for your source
36
+ def call(command, definition)
37
+ Bundler.ui.silence { definition.resolve_remotely! }
38
+
39
+ instance = new(definition)
40
+
41
+ case command
42
+ when Commands::INSTALL, Commands::EXEC then instance.build_install
43
+ when Commands::UPDATE then instance.build_update
44
+ else
45
+ raise ArgumentError, "invalid command: #{command}"
46
+ end
47
+ end
48
+ end
49
+
50
+ # @param definition [Bundler::Definition] definition for your source
51
+ #
52
+ # @return [Hash] local dependencies
53
+ def initialize(definition)
54
+ @definition = definition
55
+ @direct_dependencies = Hash[definition.dependencies.map { |val| [val.name, val] }]
56
+ # Support case without Gemfile.lock
57
+ @locked_specs = @definition.locked_gems ? @definition.locked_gems.specs : []
58
+ end
59
+
60
+ # Build install specification
61
+ #
62
+ # @return [Hash]
63
+ def build_install
64
+ hash = build_main
65
+
66
+ @definition.specs.each do |spec|
67
+ next if skip?(spec.source)
68
+
69
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
70
+
71
+ hash['dependencies'][spec.name] = {
72
+ 'platform' => build_spec_platform(spec, locked_spec),
73
+ 'source' => build_spec_source(spec),
74
+ 'type' => build_dependency_type(spec.name),
75
+ 'versions' => build_versions(spec, locked_spec)
76
+ }
77
+ end
78
+
79
+ hash
80
+ end
81
+
82
+ # Build update specification
83
+ #
84
+ # @return [Hash]
85
+ def build_update
86
+ hash = build_main
87
+
88
+ @definition.specs.each do |spec|
89
+ next if skip?(spec.source)
90
+
91
+ locked_spec = @locked_specs.find { |s| s.name == spec.name }
92
+
93
+ hash['dependencies'][spec.name] = {
94
+ 'platform' => build_spec_platform(spec, locked_spec),
95
+ 'source' => build_spec_source(spec),
96
+ 'type' => build_dependency_type(spec.name),
97
+ 'versions' => build_versions(spec, locked_spec)
98
+ }
99
+ end
100
+
101
+ hash
102
+ end
103
+
104
+ private
105
+
106
+ # Build default specification
107
+ #
108
+ # @return [Hash]
109
+ def build_main
110
+ {
111
+ 'dependencies' => {},
112
+ 'sources' => build_sources,
113
+ 'plugins' => {},
114
+ 'platforms' => @definition.platforms.map(&:to_s)
115
+ }
116
+ end
117
+
118
+ # Build gem versions
119
+ #
120
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
121
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
122
+ #
123
+ # @return [Array<String>]
124
+ def build_versions(spec, locked_spec = nil)
125
+ if locked_spec && locked_spec.version.to_s != spec.version.to_s
126
+ [locked_spec.version.to_s, spec.version.to_s]
127
+ else
128
+ [spec.version.to_s]
129
+ end
130
+ end
131
+
132
+ # @param specs [Array] specs that are direct dependencies
133
+ # @param name [String] spec name
134
+ #
135
+ # @return [Boolean] dependency type
136
+ def build_dependency_type(name)
137
+ if @direct_dependencies.key?(name)
138
+ DEPENDENCIES_TYPES[:direct]
139
+ else
140
+ DEPENDENCIES_TYPES[:dependency]
141
+ end
142
+ end
143
+
144
+ # Build gem platform
145
+ #
146
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
147
+ # @param locked_spec [Bundler::LazySpecification, Gem::Specification, NilClass]
148
+ #
149
+ # @return [String]
150
+ def build_spec_platform(spec, locked_spec)
151
+ parse_platform(
152
+ spec.platform || locked_spec&.platform || spec.send(:generic_local_platform)
153
+ )
154
+ end
155
+
156
+ # Parse gem platform
157
+ #
158
+ # @param platform [String, Gem::Platform]
159
+ #
160
+ # @return [String]
161
+ def parse_platform(platform)
162
+ case platform
163
+ when String then platform
164
+ when Gem::Platform then platform.to_s
165
+ end
166
+ end
167
+
168
+ # Build gem source type
169
+ #
170
+ # @param source [Bundler::Source] gem source type
171
+ #
172
+ # @return [Integer] internal gem source type
173
+ def build_spec_gem_source_type(source)
174
+ case source
175
+ when Bundler::Source::Metadata
176
+ GEM_SOURCES_TYPES[:local]
177
+ when Bundler::Source::Rubygems, Bundler::Source::Rubygems::Remote
178
+ GEM_SOURCES_TYPES[:gemfile_source]
179
+ when Bundler::Source::Git
180
+ GEM_SOURCES_TYPES[:gemfile_git]
181
+ when Bundler::Source::Path
182
+ GEM_SOURCES_TYPES[:gemfile_path]
183
+ else
184
+ raise ArgumentError, "unknown source #{source.class}"
185
+ end
186
+ end
187
+
188
+ # Build gem source
189
+ #
190
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
191
+ #
192
+ # @return [Hash]
193
+ def build_spec_source(spec)
194
+ source = source_for_spec(spec)
195
+
196
+ {
197
+ 'type' => build_spec_gem_source_type(source),
198
+ 'value' => source_name_from_source(source)
199
+ }
200
+ end
201
+
202
+ # Figure out source for gem
203
+ #
204
+ # @param spec [Bundler::StubSpecification, Bundler::LazySpecification, Gem::Specification]
205
+ #
206
+ # @return [Bundler::Source] gem source type
207
+ def source_for_spec(spec)
208
+ return spec.remote if spec.remote
209
+
210
+ case spec.source
211
+ when Bundler::Source::Rubygems
212
+ spec
213
+ .source
214
+ .send(:remote_specs)
215
+ .search(Bundler::Dependency.new(spec.name, spec.version))
216
+ .last
217
+ .remote
218
+ when Bundler::Source::Metadata, Bundler::Source::Git, Bundler::Source::Path
219
+ spec.source
220
+ else
221
+ raise ArgumentError, "unknown source #{spec.source.class}"
222
+ end
223
+ end
224
+
225
+ # Build gem source name
226
+ #
227
+ # @param source [Bundler::Source] gem source type
228
+ #
229
+ # @return [String]
230
+ def source_name_from_source(source)
231
+ case source
232
+ when Bundler::Source::Metadata
233
+ ''
234
+ when Bundler::Source::Rubygems::Remote
235
+ source_name(source.anonymized_uri)
236
+ when Bundler::Source::Git
237
+ source.instance_variable_get(:@safe_uri)
238
+ when Bundler::Source::Path
239
+ source.path
240
+ else
241
+ raise ArgumentError, "unknown source #{source.class}"
242
+ end
243
+ end
244
+
245
+ # @param uri [Bundler::URI]
246
+ #
247
+ # @return [String]
248
+ def source_name(uri)
249
+ uri.to_s[0...-1]
250
+ end
251
+
252
+ # Build sources used in the Gemfile
253
+ #
254
+ # @return [Array<Hash>]
255
+ def build_sources
256
+ sources = @definition.send(:sources).rubygems_sources
257
+ hash = {}
258
+
259
+ sources.each do |source|
260
+ type = build_source_type(source.remotes)
261
+
262
+ source.remotes.each do |src|
263
+ hash[source_name(src)] = type
264
+ end
265
+ end
266
+
267
+ hash.map { |name, type| { 'name' => name, 'type' => type } }
268
+ end
269
+
270
+ # Build gem source type
271
+ #
272
+ # @param remotes [Array<Bundler::URI>]
273
+ #
274
+ # @return [Integer] internal source type
275
+ def build_source_type(remotes)
276
+ remotes.count > 1 ? SOURCES_TYPES[:multiple_primary] : SOURCES_TYPES[:valid]
277
+ end
278
+
279
+ # Checks if we should skip a source
280
+ #
281
+ # @param source [Bundler::Source] gem source type
282
+ #
283
+ # @return [Boolean] true if we should skip this source, false otherwise
284
+ def skip?(source)
285
+ return true if me?(source)
286
+
287
+ false
288
+ end
289
+
290
+ # Checks if it's a self source, this happens for repositories that are a gem
291
+ #
292
+ # @param source [Bundler::Source] gem source type
293
+ #
294
+ # @return [Boolean] true if it's a self source, false otherwise
295
+ def me?(source)
296
+ return false unless ME_SOURCES.include?(source.class)
297
+
298
+ source.path.to_s == ME_PATH
299
+ end
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Module responsible for building local context
5
+ module LocalContext
6
+ # Module responsible for building platform information from local context
7
+ module Platform
8
+ class << self
9
+ # Build platform information
10
+ #
11
+ # @return [Hash]
12
+ def call
13
+ {
14
+ 'bundler' => {
15
+ 'version' => Bundler::VERSION
16
+ },
17
+ 'environment' => environment,
18
+ 'ruby' => ruby_information,
19
+ 'rubygems' => {
20
+ 'specification_version' => Gem::Specification::CURRENT_SPECIFICATION_VERSION,
21
+ 'version' => Gem::VERSION
22
+ }
23
+ }.freeze
24
+ end
25
+
26
+ private
27
+
28
+ # Build platform ruby information
29
+ #
30
+ # @return [Hash]
31
+ def ruby_information
32
+ if defined?(JRUBY_VERSION)
33
+ revision = JRUBY_REVISION.to_s
34
+ version = JRUBY_VERSION
35
+ else
36
+ revision = RUBY_REVISION.to_s
37
+ version = RUBY_ENGINE_VERSION
38
+ end
39
+
40
+ {
41
+ 'engine' => RUBY_ENGINE,
42
+ 'patchlevel' => RUBY_PATCHLEVEL,
43
+ 'release_date' => RUBY_RELEASE_DATE,
44
+ 'revision' => revision,
45
+ 'version' => version
46
+ }
47
+ end
48
+
49
+ # Build platform environment information
50
+ #
51
+ # @return [String]
52
+ def environment
53
+ ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Diffend
4
+ # Diffend logging
5
+ class Logger
6
+ # Low-level information, mostly for developers.
7
+ DEBUG = 0
8
+ # Generic (useful) information about system operation.
9
+ INFO = 1
10
+ # A warning.
11
+ WARN = 2
12
+ # A handleable error condition.
13
+ ERROR = 3
14
+ # An unhandleable error that results in a program crash.
15
+ FATAL = 4
16
+ # An unknown message that should always be logged.
17
+ UNKNOWN = 5
18
+
19
+ # @param level [Integer] logging severity threshold
20
+ def initialize(level = INFO)
21
+ @level = level
22
+ end
23
+
24
+ # @param message [String]
25
+ def debug(message)
26
+ log(DEBUG, message)
27
+ end
28
+
29
+ # @param message [String]
30
+ def info(message)
31
+ log(INFO, message)
32
+ end
33
+
34
+ # @param message [String]
35
+ def warn(message)
36
+ log(WARN, message)
37
+ end
38
+
39
+ # @param message [String]
40
+ def error(message)
41
+ log(ERROR, message)
42
+ end
43
+
44
+ # @param message [String]
45
+ def fatal(message)
46
+ log(FATAL, message)
47
+ end
48
+
49
+ private
50
+
51
+ # @param severity [Integer]
52
+ # @param message [String]
53
+ def log(severity, message)
54
+ return if severity < @level
55
+
56
+ case severity
57
+ when INFO
58
+ Bundler.ui.confirm(message)
59
+ when WARN
60
+ Bundler.ui.warn(message)
61
+ when ERROR, FATAL
62
+ Bundler.ui.error(message)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,30 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  %w[
4
- build_bundler_definition
4
+ version
5
+ logger
5
6
  errors
6
- config/fetcher
7
- config/file_finder
8
- config/validator
7
+ build_bundler_definition
9
8
  commands
9
+ config
10
+ configs/fetcher
11
+ configs/validator
10
12
  handle_errors/messages
11
13
  handle_errors/build_exception_payload
12
14
  handle_errors/display_to_stdout
13
15
  handle_errors/report
14
16
  request_object
15
17
  request
16
- voting
18
+ local_context/diffend
19
+ local_context/host
20
+ local_context/packages
21
+ local_context/platform
22
+ local_context
23
+ request_verdict
24
+ execute
17
25
  track
18
26
  ].each { |file| require "diffend/#{file}" }
19
27
 
20
- %w[
21
- versions/local
22
- versions/remote
23
- ].each { |file| require "diffend/voting/#{file}" }
28
+ begin
29
+ config = Diffend::Config.new(
30
+ command: Diffend::Commands::EXEC,
31
+ severity: Diffend::Logger::FATAL
32
+ )
33
+ rescue Diffend::Errors::HandledException
34
+ # we silent exit here because we don't want to break client boot
35
+ return
36
+ end
37
+
38
+ return if %w[development test].include?(config.env)
24
39
 
25
- unless %w[development test].include?(ENV['DIFFEND_ENV'])
26
- Thread.new do
27
- track = Diffend::Track.new
28
- track.start
29
- end
40
+ Thread.new do
41
+ track = Diffend::Track.new(config)
42
+ track.start
30
43
  end