mutant 0.11.34 → 0.12.0

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