mutant 0.11.24 → 0.11.25
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 +4 -4
- data/lib/mutant/license/subscription/commercial.rb +65 -31
- data/lib/mutant/license/subscription/opensource.rb +2 -55
- data/lib/mutant/license/subscription/repository.rb +72 -0
- data/lib/mutant/license/subscription.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant.rb +2 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 582339f240c2c234a6130ff32d7c998318b9b82670321483d5b66351524acfb9
|
4
|
+
data.tar.gz: 1f027e4239fc3bb5b518e796249ab4ac9cf2902d938995adfbd276af2fb69951
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 823420ff1abcf0b8ac2e8c79012962a355f85324195cefc4d1daf9a60537f5773d2d125ec76881462b6f59d61081a2875c9f5c168ede8cbab190f7cc45a9a665
|
7
|
+
data.tar.gz: 1ebafd946b6b3404835653a3a024e655b9961d418247201ba14080fb772df20cab6295609acaee00d41bd9820f8fdb492b8b0606791435be395f863588cde104
|
@@ -4,50 +4,84 @@ module Mutant
|
|
4
4
|
module License
|
5
5
|
class Subscription
|
6
6
|
class Commercial < self
|
7
|
-
|
8
|
-
include Anima.new(:email)
|
9
|
-
|
10
|
-
alias_method :to_s, :email
|
11
|
-
public :to_s
|
12
|
-
end
|
7
|
+
include AbstractType
|
13
8
|
|
14
9
|
def self.from_json(value)
|
15
|
-
|
10
|
+
{
|
11
|
+
'individual' => Individual,
|
12
|
+
'organization' => Organization
|
13
|
+
}.fetch(value.fetch('type', 'individual')).from_json(value)
|
16
14
|
end
|
17
15
|
|
18
|
-
|
19
|
-
|
16
|
+
class Organization < self
|
17
|
+
SUBSCRIPTION_NAME = 'commercial organization'
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
else
|
24
|
-
failure(licensed, candidates)
|
19
|
+
def self.from_json(value)
|
20
|
+
new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
|
25
21
|
end
|
26
|
-
end
|
27
22
|
|
28
|
-
|
23
|
+
def call(world)
|
24
|
+
Repository.load_from_git(world).bind(&method(:check_subscription))
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
git_author(world).merge(commit_author(world))
|
32
|
-
end
|
27
|
+
private
|
33
28
|
|
34
|
-
|
35
|
-
|
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
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
38
|
+
class Individual < self
|
39
|
+
SUBSCRIPTION_NAME = 'commercial individual'
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
50
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
|
51
85
|
end # Commercial
|
52
86
|
end # Subscription
|
53
87
|
end # License
|
@@ -4,63 +4,14 @@ module Mutant
|
|
4
4
|
module License
|
5
5
|
class Subscription
|
6
6
|
class Opensource < self
|
7
|
-
|
8
|
-
include Anima.new(:host, :path)
|
9
|
-
|
10
|
-
REMOTE_REGEXP = /\A[^\t]+\t(?<url>[^ ]+) \((?:fetch|push)\)\n\z/.freeze
|
11
|
-
GIT_SSH_REGEXP = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}.freeze
|
12
|
-
GIT_HTTPS_REGEXP = %r{\Ahttps://(?<host>[^/]+)/(?<path>.+?)(?:\.git)?\z}.freeze
|
13
|
-
|
14
|
-
private_constant(*constants(false))
|
15
|
-
|
16
|
-
def to_s
|
17
|
-
[host, path].join('/')
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.parse(input)
|
21
|
-
host, path = *input.split('/', 2).map(&:downcase)
|
22
|
-
new(host: host, path: path)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.parse_remote(input)
|
26
|
-
match = REMOTE_REGEXP.match(input) or
|
27
|
-
fail "Unmatched remote line: #{input.inspect}"
|
28
|
-
|
29
|
-
parse_url(match[:url])
|
30
|
-
end
|
31
|
-
private_class_method :parse_remote
|
32
|
-
|
33
|
-
def self.parse_url(input)
|
34
|
-
match = GIT_SSH_REGEXP.match(input) || GIT_HTTPS_REGEXP.match(input)
|
35
|
-
|
36
|
-
unless match
|
37
|
-
fail "Unmatched git remote URL: #{input.inspect}"
|
38
|
-
end
|
39
|
-
|
40
|
-
new(host: match[:host], path: match[:path].downcase)
|
41
|
-
end
|
42
|
-
private_class_method :parse_url
|
43
|
-
|
44
|
-
def allow?(other)
|
45
|
-
other.host.eql?(host) && path_match?(other.path)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def path_match?(other_path)
|
51
|
-
path.eql?(other_path) || (path.end_with?('/*') && other_path.start_with?(path[..-2]))
|
52
|
-
end
|
53
|
-
end # Opensource
|
7
|
+
SUBSCRIPTION_NAME = 'opensource repository'
|
54
8
|
|
55
9
|
def self.from_json(value)
|
56
10
|
new(licensed: value.fetch('repositories').map(&Repository.public_method(:parse)).to_set)
|
57
11
|
end
|
58
12
|
|
59
13
|
def call(world)
|
60
|
-
world
|
61
|
-
.capture_stdout(%w[git remote --verbose])
|
62
|
-
.fmap(&method(:parse_remotes))
|
63
|
-
.bind(&method(:check_subscription))
|
14
|
+
Repository.load_from_git(world).bind(&method(:check_subscription))
|
64
15
|
end
|
65
16
|
|
66
17
|
private
|
@@ -73,10 +24,6 @@ module Mutant
|
|
73
24
|
end
|
74
25
|
end
|
75
26
|
|
76
|
-
def parse_remotes(input)
|
77
|
-
input.lines.map(&Repository.method(:parse_remote)).to_set
|
78
|
-
end
|
79
|
-
|
80
27
|
end # Opensource
|
81
28
|
end # Subscription
|
82
29
|
end # License
|
@@ -0,0 +1,72 @@
|
|
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/.freeze
|
10
|
+
GIT_SSH_REGEXP = %r{\A[^@]+@(?<host>[^:/]+)[:/](?<path>.+?)(?:\.git)?\z}.freeze
|
11
|
+
GIT_HTTPS_REGEXP = %r{\Ahttps://(?<host>[^/]+)/(?<path>.+?)(?:\.git)?\z}.freeze
|
12
|
+
WILDCARD = '/*'
|
13
|
+
WILDCARD_RANGE = (..-WILDCARD.length).freeze
|
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
|
data/lib/mutant/version.rb
CHANGED
data/lib/mutant.rb
CHANGED
@@ -251,8 +251,9 @@ module Mutant
|
|
251
251
|
require 'mutant/range'
|
252
252
|
require 'mutant/license'
|
253
253
|
require 'mutant/license/subscription'
|
254
|
-
require 'mutant/license/subscription/opensource'
|
255
254
|
require 'mutant/license/subscription/commercial'
|
255
|
+
require 'mutant/license/subscription/opensource'
|
256
|
+
require 'mutant/license/subscription/repository'
|
256
257
|
require 'mutant/segment'
|
257
258
|
require 'mutant/segment/recorder'
|
258
259
|
end
|
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.
|
4
|
+
version: 0.11.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diff-lcs
|
@@ -220,6 +220,7 @@ files:
|
|
220
220
|
- lib/mutant/license/subscription.rb
|
221
221
|
- lib/mutant/license/subscription/commercial.rb
|
222
222
|
- lib/mutant/license/subscription/opensource.rb
|
223
|
+
- lib/mutant/license/subscription/repository.rb
|
223
224
|
- lib/mutant/loader.rb
|
224
225
|
- lib/mutant/matcher.rb
|
225
226
|
- lib/mutant/matcher/chain.rb
|