mutant 0.11.34 → 0.12.0

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: e98171c271934f978770ae00e52d0e3e801a4197fa4b5efb0a43f966ff5af54c
4
- data.tar.gz: 0d2d7823052db9d2a46efcc0fdd11808d95510dd58a77933288c063f7195851f
3
+ metadata.gz: 4e8ba758de42528dd4dd4fdb5686df439d9ea4e2b1635905e89d7a98b904b959
4
+ data.tar.gz: df2317b0cabc5964fec52e0fc1d7e76c0f368a01f713fa411f03cba4808b834a
5
5
  SHA512:
6
- metadata.gz: ba1991d33cb05098cb78bc5325d05c8b4dbe974752a276a5daf43139c1e1202bb5ce5505b2ce1072d8d86ca4ca6ca22a828d971589b1c22b13fd012703cf7ebf
7
- data.tar.gz: 8e3f0a5ce588b5b49c08233bceb8c855c6b32ce7cbb4fb1a1056e981775e9007c7188b09e73438fb56d7faff64c6f13b280dbed580273b329b3981693123b3dd
6
+ metadata.gz: 3b74495aa82f4489e22a95b5c25f3185d759fa616354af51c07544bb66be08f69becf8e5021db80008d169c2de12e677bf8a3a38becb954c32dc8287f1eea24d
7
+ data.tar.gz: 82e7bdc18591e89028a39a3489291452b0b73cc4bcc6ea7549e9fa376778de622ac53bd4a2dbbe7702ff875eb9d84f55b6fa1ad424e55bfb0e4c7bdaa7243d13
@@ -9,13 +9,6 @@ module Mutant
9
9
  SHORT_DESCRIPTION = 'Run code analysis'
10
10
  SUBCOMMANDS = EMPTY_ARRAY
11
11
 
12
- UNLICENSED = <<~MESSAGE.lines.freeze
13
- You are using mutant unlicensed.
14
-
15
- See https://github.com/mbj/mutant#licensing to aquire a license.
16
- Note: Its free for opensource use, which is recommended for trials.
17
- MESSAGE
18
-
19
12
  NO_TESTS_MESSAGE = <<~'MESSAGE'
20
13
  ===============
21
14
  Mutant found no tests available for mutation testing.
@@ -34,8 +27,8 @@ module Mutant
34
27
  private
35
28
 
36
29
  def action
37
- License.call(world)
38
- .bind { bootstrap }
30
+ bootstrap
31
+ .bind(&method(:verify_usage))
39
32
  .bind(&method(:validate_tests))
40
33
  .bind(&Mutation::Runner.public_method(:call))
41
34
  .bind(&method(:from_result))
@@ -56,6 +49,10 @@ module Mutant
56
49
  Either::Left.new('Uncovered mutations detected, exiting nonzero!')
57
50
  end
58
51
  end
52
+
53
+ def verify_usage(environment)
54
+ environment.config.usage.verify.fmap { environment }
55
+ end
59
56
  end # Run
60
57
  end # Environment
61
58
  end # Command
@@ -15,6 +15,7 @@ module Mutant
15
15
  add_integration_options
16
16
  add_matcher_options
17
17
  add_reporter_options
18
+ add_usage_options
18
19
  ].freeze
19
20
 
20
21
  private
@@ -136,6 +137,20 @@ module Mutant
136
137
  set(reporter: @config.reporter.with(print_warnings: true))
137
138
  end
138
139
  end
140
+
141
+ def add_usage_options(parser)
142
+ parser.separator('Usage:')
143
+
144
+ parser.accept(Usage, Usage::CLI_REGEXP) do |value|
145
+ Usage.parse(value).from_right
146
+ end
147
+
148
+ parser.on(
149
+ '--usage USAGE_TYPE',
150
+ Usage,
151
+ 'License usage: opensource|commercial'
152
+ ) { |usage| set(usage: usage) }
153
+ end
139
154
  end # Run
140
155
  # rubocop:enable Metrics/ClassLength
141
156
  end # Command
@@ -10,7 +10,7 @@ module Mutant
10
10
  class Root < self
11
11
  NAME = 'mutant'
12
12
  SHORT_DESCRIPTION = 'mutation testing engine main command'
13
- SUBCOMMANDS = [Environment::Run, Environment, Subscription, Util].freeze
13
+ SUBCOMMANDS = [Environment::Run, Environment, Util].freeze
14
14
  end # Root
15
15
  end # Command
16
16
  end # CLI
@@ -122,7 +122,7 @@ module Mutant
122
122
 
123
123
  def parse(arguments)
124
124
  Either
125
- .wrap_error(OptionParser::InvalidOption) { parser.order(arguments) }
125
+ .wrap_error(OptionParser::InvalidArgument, OptionParser::InvalidOption) { parser.order(arguments) }
126
126
  .lmap(&method(:with_help))
127
127
  .bind(&method(:parse_remaining))
128
128
  end
@@ -176,14 +176,6 @@ module Mutant
176
176
  end
177
177
  end
178
178
 
179
- def parse_remaining_arguments(remaining)
180
- if remaining.any?
181
- Either::Left.new("#{full_name}: Does not expect extra arguments")
182
- else
183
- Either::Right.new(self)
184
- end
185
- end
186
-
187
179
  def parse_subcommand(arguments)
188
180
  command_name, *arguments = arguments
189
181
 
data/lib/mutant/config.rb CHANGED
@@ -21,7 +21,8 @@ module Mutant
21
21
  :matcher,
22
22
  :mutation,
23
23
  :reporter,
24
- :requires
24
+ :requires,
25
+ :usage
25
26
  )
26
27
 
27
28
  %i[fail_fast].each do |name|
@@ -87,7 +88,8 @@ module Mutant
87
88
  jobs: other.jobs || jobs,
88
89
  matcher: matcher.merge(other.matcher),
89
90
  mutation: mutation.merge(other.mutation),
90
- requires: requires + other.requires
91
+ requires: requires + other.requires,
92
+ usage: other.usage.merge(usage)
91
93
  )
92
94
  end
93
95
  # rubocop:enable Metrics/AbcSize
@@ -247,6 +249,10 @@ module Mutant
247
249
  Transform::Hash::Key.new(
248
250
  transform: Transform::STRING_ARRAY,
249
251
  value: 'requires'
252
+ ),
253
+ Transform::Hash::Key.new(
254
+ transform: Usage::TRANSFORM,
255
+ value: 'usage'
250
256
  )
251
257
  ],
252
258
  required: []
@@ -15,6 +15,7 @@ module Mutant
15
15
  #
16
16
  # rubocop:disable Metrics/AbcSize
17
17
  def run
18
+ info 'Usage: %s', object.usage.value
18
19
  info 'Matcher: %s', object.matcher.inspect
19
20
  info 'Integration: %s', object.integration.name || 'null'
20
21
  info 'Jobs: %s', object.jobs || 'auto'
@@ -36,9 +36,8 @@ module Mutant
36
36
 
37
37
  def repository_root
38
38
  world
39
- .capture_stdout(%w[git rev-parse --show-toplevel])
40
- .fmap(&:chomp)
41
- .fmap(&world.pathname.public_method(:new))
39
+ .capture_command(%w[git rev-parse --show-toplevel])
40
+ .fmap { |status| world.pathname.new(status.stdout.chomp) }
42
41
  end
43
42
 
44
43
  def touched_path(path, &block)
@@ -52,11 +51,10 @@ module Mutant
52
51
 
53
52
  def diff_index(root)
54
53
  world
55
- .capture_stdout(%W[git diff-index #{to}])
56
- .fmap(&:lines)
57
- .bind do |lines|
54
+ .capture_command(%W[git diff-index #{to}])
55
+ .bind do |status|
58
56
  Mutant
59
- .traverse(->(line) { parse_line(root, line) }, lines)
57
+ .traverse(->(line) { parse_line(root, line) }, status.stdout.lines)
60
58
  .fmap do |paths|
61
59
  paths.to_h { |path| [path.path, path] }
62
60
  end
@@ -105,8 +103,8 @@ module Mutant
105
103
 
106
104
  def diff_ranges
107
105
  world
108
- .capture_stdout(%W[git diff --unified=0 #{to} -- #{path}])
109
- .fmap(&Ranges.public_method(:parse))
106
+ .capture_command(%W[git diff --unified=0 #{to} -- #{path}])
107
+ .fmap { |status| Ranges.parse(status.stdout) }
110
108
  .from_right
111
109
  end
112
110
  memoize :diff_ranges
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Usage
5
+ include Adamantium, Equalizer.new
6
+
7
+ def value
8
+ self.class::VALUE
9
+ end
10
+
11
+ def verify
12
+ Either::Right.new(nil)
13
+ end
14
+
15
+ def message
16
+ self.class::MESSAGE
17
+ end
18
+
19
+ def merge(_other)
20
+ self
21
+ end
22
+
23
+ class Commercial < self
24
+ VALUE = 'commercial'
25
+
26
+ MESSAGE = <<~'MESSAGE'
27
+ ## Commercial use
28
+
29
+ `commercial` usage type requires [payment](https://github.com/mbj/mutant?tab=readme-ov-file#pricing),
30
+ If you are under an active payment plan you can use the commercial usage type on any
31
+ repository, including private ones.
32
+
33
+ To use `commercial` usage type either specify `--usage commercial` on the command
34
+ line or use the config file key `usage`:
35
+
36
+ ```
37
+ # mutant.yml or config/mutant.yml
38
+ usage: commercial
39
+ ```
40
+ MESSAGE
41
+ end
42
+
43
+ class Opensource < self
44
+ VALUE = 'opensource'
45
+
46
+ MESSAGE = <<~'MESSAGE'
47
+ ## Opensource use
48
+
49
+ `opensource` usage is free while mutant is run on an opensource project.
50
+ Under that usage mutant does not require any kind of sign up or payment.
51
+ Set this usage type exclusively on public opensource projects. Any other
52
+ scenario requires payment.
53
+ Using the `opensource` usage type on private repotiories and or on commercial
54
+ code bases is not valid.
55
+
56
+ To use `opensource` usage type either specify `--usage opensource` on the command
57
+ line or use the config file key `usage`:
58
+
59
+ ```
60
+ # mutant.yml or config/mutant.yml
61
+ usage: opensource
62
+ ```
63
+ MESSAGE
64
+ end
65
+
66
+ class Unknown < self
67
+ VALUE = 'unknown'
68
+
69
+ MESSAGE = <<~"MESSAGE".freeze
70
+ # Unknown mutant usage type
71
+
72
+ Mutant license usage is unspecified. Valid usage types are `opensource` or `commercial`.
73
+
74
+ Usage can be specified via the `--usage` command line parameter or via the
75
+ config file under the `usage` key.
76
+
77
+ #{Commercial::MESSAGE}
78
+ #{Opensource::MESSAGE}
79
+ This is a breaking change for users of the 0.11.x / 0.10.x mutant releases.
80
+ Sorry for that but its going to make future adoption much easier.
81
+ License gem is gone entirely.
82
+ MESSAGE
83
+
84
+ def merge(other)
85
+ other
86
+ end
87
+
88
+ def verify
89
+ Either::Left.new(MESSAGE)
90
+ end
91
+ end
92
+
93
+ def self.parse(value)
94
+ {
95
+ 'commercial' => Either::Right.new(Commercial.new),
96
+ 'opensource' => Either::Right.new(Opensource.new)
97
+ }.fetch(value) { Either::Left.new("Unknown usage option: #{value.inspect}") }
98
+ end
99
+
100
+ CLI_REGEXP = /\A(?:commercial|opensource)\z/
101
+
102
+ TRANSFORM = Transform::Sequence.new(
103
+ steps: [
104
+ Transform::STRING,
105
+ Transform::Block.capture(:environment_variables, &method(:parse))
106
+ ]
107
+ )
108
+ end # Usage
109
+ end # Mutant
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.34'
5
+ VERSION = '0.12.0'
6
6
  end # Mutant
data/lib/mutant/world.rb CHANGED
@@ -39,19 +39,25 @@ module Mutant
39
39
  INSPECT
40
40
  end
41
41
 
42
+ class CommandStatus
43
+ include Adamantium, Anima.new(:process_status, :stderr, :stdout)
44
+ end # CommandStatus
45
+
42
46
  # Capture stdout of a command
43
47
  #
44
48
  # @param [Array<String>] command
45
49
  #
46
- # @return [Either<String,String>]
47
- def capture_stdout(command)
48
- stdout, status = open3.capture2(*command, binmode: true)
50
+ # @return [Either<CommandStatus,CommandStatus>]
51
+ def capture_command(command)
52
+ stdout, stderr, process_status = open3.capture3(*command, binmode: true)
49
53
 
50
- if status.success?
51
- Either::Right.new(stdout)
52
- else
53
- Either::Left.new("Command #{command} failed!")
54
- end
54
+ (process_status.success? ? Either::Right : Either::Left).new(
55
+ CommandStatus.new(
56
+ process_status: process_status,
57
+ stderr: stderr,
58
+ stdout: stdout
59
+ )
60
+ )
55
61
  end
56
62
 
57
63
  # Try const get
data/lib/mutant.rb CHANGED
@@ -109,6 +109,7 @@ module Mutant
109
109
  require 'mutant/require_highjack'
110
110
  require 'mutant/mutation'
111
111
  require 'mutant/mutation/operators'
112
+ require 'mutant/usage'
112
113
  require 'mutant/mutation/config'
113
114
  require 'mutant/mutator'
114
115
  require 'mutant/mutator/util'
@@ -221,7 +222,6 @@ module Mutant
221
222
  require 'mutant/config/coverage_criteria'
222
223
  require 'mutant/cli'
223
224
  require 'mutant/cli/command'
224
- require 'mutant/cli/command/subscription'
225
225
  require 'mutant/cli/command/environment'
226
226
  require 'mutant/cli/command/environment/irb'
227
227
  require 'mutant/cli/command/environment/run'
@@ -255,11 +255,6 @@ module Mutant
255
255
  require 'mutant/repository/diff/ranges'
256
256
  require 'mutant/zombifier'
257
257
  require 'mutant/range'
258
- require 'mutant/license'
259
- require 'mutant/license/subscription'
260
- require 'mutant/license/subscription/commercial'
261
- require 'mutant/license/subscription/opensource'
262
- require 'mutant/license/subscription/repository'
263
258
  require 'mutant/segment'
264
259
  require 'mutant/segment/recorder'
265
260
  end
@@ -363,7 +358,8 @@ module Mutant
363
358
  matcher: Matcher::Config::DEFAULT,
364
359
  mutation: Mutation::Config::EMPTY,
365
360
  reporter: Reporter::CLI.build(WORLD.stdout),
366
- requires: EMPTY_ARRAY
361
+ requires: EMPTY_ARRAY,
362
+ usage: Usage::Unknown.new
367
363
  )
368
364
  end # Config
369
365
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.34
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-26 00:00:00.000000000 Z
11
+ date: 2024-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -177,7 +177,6 @@ files:
177
177
  - lib/mutant/cli/command/environment/subject.rb
178
178
  - lib/mutant/cli/command/environment/test.rb
179
179
  - lib/mutant/cli/command/root.rb
180
- - lib/mutant/cli/command/subscription.rb
181
180
  - lib/mutant/cli/command/util.rb
182
181
  - lib/mutant/config.rb
183
182
  - lib/mutant/config/coverage_criteria.rb
@@ -197,11 +196,6 @@ files:
197
196
  - lib/mutant/isolation/exception.rb
198
197
  - lib/mutant/isolation/fork.rb
199
198
  - lib/mutant/isolation/none.rb
200
- - lib/mutant/license.rb
201
- - lib/mutant/license/subscription.rb
202
- - lib/mutant/license/subscription/commercial.rb
203
- - lib/mutant/license/subscription/opensource.rb
204
- - lib/mutant/license/subscription/repository.rb
205
199
  - lib/mutant/loader.rb
206
200
  - lib/mutant/matcher.rb
207
201
  - lib/mutant/matcher/chain.rb
@@ -341,6 +335,7 @@ files:
341
335
  - lib/mutant/test/runner/sink.rb
342
336
  - lib/mutant/timer.rb
343
337
  - lib/mutant/transform.rb
338
+ - lib/mutant/usage.rb
344
339
  - lib/mutant/util.rb
345
340
  - lib/mutant/variable.rb
346
341
  - lib/mutant/version.rb
@@ -366,7 +361,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
366
361
  - !ruby/object:Gem::Version
367
362
  version: '0'
368
363
  requirements: []
369
- rubygems_version: 3.3.25
364
+ rubygems_version: 3.5.3
370
365
  signing_key:
371
366
  specification_version: 4
372
367
  summary: ''
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module CLI
5
- class Command
6
- class Subscription < self
7
- NAME = 'subscription'
8
- SHORT_DESCRIPTION = 'Subscription subcommands'
9
-
10
- private
11
-
12
- def license
13
- License.call(world)
14
- end
15
-
16
- class Test < self
17
- NAME = 'test'
18
- SUBCOMMANDS = [].freeze
19
- SHORT_DESCRIPTION = 'Silently validates subscription, exits accordingly'
20
-
21
- private
22
-
23
- def execute
24
- license.right?
25
- end
26
- end # Test
27
-
28
- class Show < self
29
- NAME = 'show'
30
- SUBCOMMANDS = [].freeze
31
- SHORT_DESCRIPTION = 'Show subscription status'
32
-
33
- private
34
-
35
- def execute
36
- license.either(method(:unlicensed), method(:licensed))
37
- end
38
-
39
- def licensed(subscription)
40
- world.stdout.puts(subscription.description)
41
- true
42
- end
43
-
44
- def unlicensed(message)
45
- world.stderr.puts(message)
46
- false
47
- end
48
- end # Show
49
-
50
- SUBCOMMANDS = [Show, Test].freeze
51
- end # Subscription
52
- end # Command
53
- end # CLI
54
- end # Mutant
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module License
5
- class Subscription
6
- class Commercial < self
7
- include AbstractType
8
-
9
- def self.from_json(value)
10
- {
11
- 'individual' => Individual,
12
- 'organization' => Organization
13
- }.fetch(value.fetch('type', 'individual')).from_json(value)
14
- end
15
-
16
- class Organization < self
17
- SUBSCRIPTION_NAME = 'commercial organization'
18
-
19
- def self.from_json(value)
20
- new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
21
- end
22
-
23
- def call(world)
24
- Repository.load_from_git(world).bind(&method(:check_subscription))
25
- end
26
-
27
- private
28
-
29
- def check_subscription(actual)
30
- if licensed.any? { |repository| actual.any? { |other| repository.allow?(other) } }
31
- success
32
- else
33
- failure(licensed, actual)
34
- end
35
- end
36
- end
37
-
38
- class Individual < self
39
- SUBSCRIPTION_NAME = 'commercial individual'
40
-
41
- class Author
42
- include Anima.new(:email)
43
-
44
- alias_method :to_s, :email
45
- public :to_s
46
- end
47
-
48
- def self.from_json(value)
49
- new(licensed: value.fetch('authors').to_set { |email| Author.new(email: email) })
50
- end
51
-
52
- def call(world)
53
- candidates = candidates(world)
54
-
55
- if (licensed & candidates).any?
56
- success
57
- else
58
- failure(licensed, candidates)
59
- end
60
- end
61
-
62
- private
63
-
64
- def candidates(world)
65
- git_author(world).merge(commit_author(world))
66
- end
67
-
68
- def git_author(world)
69
- capture(world, %w[git config --get user.email])
70
- end
71
-
72
- def commit_author(world)
73
- capture(world, %w[git show --quiet --pretty=format:%ae])
74
- end
75
-
76
- def capture(world, command)
77
- world
78
- .capture_stdout(command)
79
- .fmap(&:chomp)
80
- .fmap { |email| Author.new(email: email) }
81
- .fmap { |value| Set.new([value]) }
82
- .from_right { Set.new }
83
- end
84
- end # Individual
85
- end # Commercial
86
- end # Subscription
87
- end # License
88
- end # Mutant
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module License
5
- class Subscription
6
- class Opensource < self
7
- SUBSCRIPTION_NAME = 'opensource repository'
8
-
9
- def self.from_json(value)
10
- new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
11
- end
12
-
13
- def call(world)
14
- Repository.load_from_git(world).bind(&method(:check_subscription))
15
- end
16
-
17
- private
18
-
19
- def check_subscription(actual)
20
- if licensed.any? { |repository| actual.any? { |other| repository.allow?(other) } }
21
- success
22
- else
23
- failure(licensed, actual)
24
- end
25
- end
26
-
27
- end # Opensource
28
- end # Subscription
29
- end # License
30
- end # Mutant
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module License
5
- class Subscription
6
- class Repository
7
- include Anima.new(:host, :path)
8
-
9
- REMOTE_REGEXP = /\A[^\t]+\t(?<url>[^ ]+) \((?:fetch|push)\)\n\z/
10
- GIT_SSH_REGEXP = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}
11
- GIT_HTTPS_REGEXP = %r{\Ahttps://(?<host>[^/]+)/(?<path>.+?)(?:\.git)?\z}
12
- WILDCARD = '/*'
13
- WILDCARD_RANGE = (..-WILDCARD.length)
14
-
15
- private_constant(*constants(false))
16
-
17
- def to_s
18
- [host, path].join('/')
19
- end
20
-
21
- def self.load_from_git(world)
22
- world
23
- .capture_stdout(%w[git remote --verbose])
24
- .fmap(&method(:parse_remotes))
25
- end
26
-
27
- def self.parse_remotes(input)
28
- input.lines.map(&method(:parse_remote)).to_set
29
- end
30
- private_class_method :parse_remotes
31
-
32
- def self.parse(input)
33
- host, path = *input.split('/', 2).map(&:downcase)
34
- new(host: host, path: path)
35
- end
36
-
37
- def self.parse_remote(input)
38
- match = REMOTE_REGEXP.match(input) or
39
- fail "Unmatched remote line: #{input.inspect}"
40
-
41
- parse_url(match[:url])
42
- end
43
- private_class_method :parse_remote
44
-
45
- def self.parse_url(input)
46
- match = GIT_SSH_REGEXP.match(input) || GIT_HTTPS_REGEXP.match(input)
47
-
48
- unless match
49
- fail "Unmatched git remote URL: #{input.inspect}"
50
- end
51
-
52
- new(host: match[:host], path: match[:path].downcase)
53
- end
54
- private_class_method :parse_url
55
-
56
- def allow?(other)
57
- other.host.eql?(host) && path_match?(other.path)
58
- end
59
-
60
- private
61
-
62
- def path_match?(other_path)
63
- path.eql?(other_path) || wildcard_match?(path, other_path) || wildcard_match?(other_path, path)
64
- end
65
-
66
- def wildcard_match?(left, right)
67
- left.end_with?(WILDCARD) && right.start_with?(left[WILDCARD_RANGE])
68
- end
69
- end # Repository
70
- end # Subscription
71
- end # License
72
- end # Mutant
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module License
5
- class Subscription
6
- include Anima.new(:licensed)
7
-
8
- FORMAT = <<~'MESSAGE'
9
- %<subscription_name>s subscription:
10
- Licensed:
11
- %<licensed>s
12
- MESSAGE
13
-
14
- FAILURE_FORMAT = <<~'MESSAGE'
15
- Can not validate %<subscription_name>s license.
16
- Licensed:
17
- %<expected>s
18
- Present:
19
- %<actual>s
20
- MESSAGE
21
-
22
- # Load value into subscription
23
- #
24
- # @param [Object] value
25
- #
26
- # @return [Subscription]
27
- def self.load(world, value)
28
- {
29
- 'com' => Commercial,
30
- 'oss' => Opensource
31
- }.fetch(value.fetch('type'))
32
- .from_json(value.fetch('contents'))
33
- .call(world)
34
- end
35
-
36
- # Subscription self description
37
- #
38
- # @return [String]
39
- def description
40
- FORMAT % {
41
- licensed: licensed.to_a.join("\n"),
42
- subscription_name: subscription_name
43
- }
44
- end
45
-
46
- private
47
-
48
- def failure(expected, actual)
49
- Either::Left.new(failure_message(expected, actual))
50
- end
51
-
52
- def success
53
- Either::Right.new(self)
54
- end
55
-
56
- def subscription_name
57
- self.class::SUBSCRIPTION_NAME
58
- end
59
-
60
- def failure_message(expected, actual)
61
- FAILURE_FORMAT % {
62
- actual: actual.any? ? actual.map(&:to_s).join("\n") : '[none]',
63
- expected: expected.map(&:to_s).join("\n"),
64
- subscription_name: subscription_name
65
- }
66
- end
67
- end # Subscription
68
- end # License
69
- end # Mutant
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- module License
5
- NAME = 'mutant-license'
6
- VERSION = ['>= 0.1', '< 0.3'].freeze
7
-
8
- # Load license
9
- #
10
- # @param [World] world
11
- #
12
- # @return [Either<String,Subscription>]
13
- #
14
- # @api private
15
- def self.call(world)
16
- load_mutant_license(world)
17
- .fmap { license_path(world) }
18
- .bind { |path| Subscription.load(world, world.json.load(path)) }
19
- end
20
-
21
- def self.load_mutant_license(world)
22
- Either
23
- .wrap_error(LoadError) { world.gem_method.call(NAME, *VERSION) }
24
- .lmap(&:message)
25
- .lmap(&method(:check_for_rubygems_mutant_license))
26
- end
27
- private_class_method :load_mutant_license
28
-
29
- def self.check_for_rubygems_mutant_license(message)
30
- if message.include?('already activated mutant-license-0.0.0')
31
- 'mutant-license gem from rubygems.org is a dummy'
32
- else
33
- message
34
- end
35
- end
36
- private_class_method :check_for_rubygems_mutant_license
37
-
38
- def self.license_path(world)
39
- world
40
- .pathname
41
- .new(world.gem.loaded_specs.fetch(NAME).full_gem_path)
42
- .join('license.json')
43
- end
44
- private_class_method :license_path
45
- end
46
- end