mudguard 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/Gemfile.lock +1 -1
- data/Guardfile +1 -1
- data/exe/mudguard +5 -12
- data/lib/mudguard/application/application.rb +19 -0
- data/lib/mudguard/domain/dependency.rb +30 -0
- data/lib/mudguard/{error.rb → domain/error.rb} +3 -1
- data/lib/mudguard/domain/policies.rb +48 -0
- data/lib/mudguard/{ruby_analyser.rb → domain/source.rb} +26 -6
- data/lib/mudguard/infrastructure/cli/controller.rb +36 -0
- data/lib/mudguard/infrastructure/cli/notification_adapter.rb +18 -0
- data/lib/mudguard/infrastructure/cli/view.rb +14 -0
- data/lib/mudguard/infrastructure/persistence/policy_file.rb +23 -0
- data/lib/mudguard/infrastructure/persistence/ruby_files.rb +36 -0
- data/lib/mudguard/version.rb +1 -1
- data/lib/mudguard.rb +2 -17
- metadata +12 -8
- data/lib/mudguard/policies.rb +0 -23
- data/lib/mudguard/policy_file.rb +0 -17
- data/lib/mudguard/ruby_files.rb +0 -17
- data/lib/tasks/gem.rake +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6b60554fbef1a22d26bcc61a3b7362f9351d3a86464e1e1e3c29f44d6f8d44f
|
4
|
+
data.tar.gz: 2a3617b3c12dc0ce2ecafdf09b6b0d9eb1464b3f51e7f93360c875fc5d63a3ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 647203da7407adc474020ab9b559847ba0cdcbf308a031ca980f02d63c45222abc52c144c03f7bbc497f24f23a37541cb37f45fd555079b44f5d95bbe6c2fcba
|
7
|
+
data.tar.gz: 576533ce4ca809ea053bb8c3ea36f6ed20b51b989f071bbfb10204b91ecf1196d82e9af4132a92b431621618b6c5e8da09d1c8d6c9c1181664a4c67111a4277d
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/Guardfile
CHANGED
@@ -12,5 +12,5 @@ guard "rspec", rspec_options do
|
|
12
12
|
watch(%r{^lib/mudguard/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
13
13
|
watch(%r{^lib/mudguard/(.+)\.rb$}) { |m| Dir.glob("spec/lib/#{m[1]}_*.rb") }
|
14
14
|
watch("spec/spec_helper.rb") { "spec" }
|
15
|
-
watch(%r{^exe\/mudguard$}) { |_| "spec/
|
15
|
+
watch(%r{^exe\/mudguard$}) { |_| "spec/exe/mudguard_spec.rb" }
|
16
16
|
end
|
data/exe/mudguard
CHANGED
@@ -1,20 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "mudguard"
|
5
|
-
require "
|
4
|
+
require "mudguard/infrastructure/cli/view"
|
5
|
+
require "mudguard/infrastructure/cli/controller"
|
6
6
|
|
7
7
|
# Checks the dependencies of a ruby project
|
8
8
|
module Mudguard
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
puts opts
|
13
|
-
exit
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
directories = parser.parse!
|
18
|
-
ok = directories.all?(&Mudguard.method(:check))
|
9
|
+
view = Mudguard::Infrastructure::Cli::View.new
|
10
|
+
parser = Mudguard::Infrastructure::Cli::Controller.new(view: view)
|
11
|
+
ok = parser.parse!(ARGV)
|
19
12
|
exit(ok ? 0 : 1)
|
20
13
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../infrastructure/persistence/policy_file"
|
4
|
+
require_relative "../infrastructure/persistence/ruby_files"
|
5
|
+
|
6
|
+
# Contains methods to check if your project is a bit muddy
|
7
|
+
module Mudguard
|
8
|
+
# API to mudguard
|
9
|
+
module Application
|
10
|
+
class << self
|
11
|
+
def check(project_path, notification)
|
12
|
+
policy_file_path = File.expand_path("MudguardFile", project_path)
|
13
|
+
policies = Infrastructure::Persistence::PolicyFile.read(policy_file_path)
|
14
|
+
|
15
|
+
policies.check(Infrastructure::Persistence::RubyFiles.all(project_path), notification)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mudguard
|
4
|
+
module Domain
|
5
|
+
# A Dependency between Modules
|
6
|
+
class Dependency
|
7
|
+
def initialize(location: nil, dependency:)
|
8
|
+
@location = location
|
9
|
+
@dependency = dependency
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"{#{@location}, #{@dependency}}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"#{@location} #{@dependency}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def match(policy)
|
21
|
+
@dependency.match(policy)
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(other)
|
25
|
+
@location == other.instance_eval { @location } &&
|
26
|
+
@dependency == other.instance_eval { @dependency }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mudguard
|
4
|
+
module Domain
|
5
|
+
# Contains the policies to be enforced
|
6
|
+
class Policies
|
7
|
+
def initialize(policies: [])
|
8
|
+
@policies = policies.map { |l| l.gsub(/\s/, "") }.map { |p| /^#{p}/ }
|
9
|
+
end
|
10
|
+
|
11
|
+
def check(sources, notification)
|
12
|
+
result = check_sources(sources, notification)
|
13
|
+
|
14
|
+
count = result[:count]
|
15
|
+
violations = result[:violations]
|
16
|
+
|
17
|
+
files = pluralize("file", count)
|
18
|
+
problems = pluralize("problem", violations)
|
19
|
+
notification.add("#{count} #{files} inspected, #{violations} #{problems} detected")
|
20
|
+
violations.zero?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def pluralize(word, count)
|
26
|
+
count == 1 ? word : "#{word}s"
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_sources(sources, notification)
|
30
|
+
sources.each_with_object(count: 0, violations: 0) do |source, result|
|
31
|
+
result[:count] += 1
|
32
|
+
dependencies = source.find_mod_dependencies
|
33
|
+
result[:violations] += check_dependencies(dependencies, notification)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_dependencies(dependencies, notification)
|
38
|
+
dependencies.reject { |d| check_dependency(d, notification) }.count
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_dependency(dependency, notification)
|
42
|
+
is_allowed = @policies.any? { |p| dependency.match(p) }
|
43
|
+
notification.add("#{dependency} not allowed") unless is_allowed
|
44
|
+
is_allowed
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,14 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "parser/current"
|
4
|
+
require "mudguard/domain/dependency"
|
4
5
|
|
5
6
|
module Mudguard
|
6
|
-
|
7
|
-
|
8
|
-
class
|
9
|
-
def
|
7
|
+
module Domain
|
8
|
+
# Represents a Ruby source file
|
9
|
+
class Source
|
10
|
+
def initialize(location: nil, code:)
|
11
|
+
@code = code
|
12
|
+
@location = location
|
13
|
+
end
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
@code == other.instance_eval { @code } && @location == other.instance_eval { @location }
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
@location
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_mod_dependencies
|
10
24
|
begin
|
11
|
-
root = Parser::CurrentRuby.parse(
|
25
|
+
root = Parser::CurrentRuby.parse(@code)
|
12
26
|
rescue Parser::SyntaxError
|
13
27
|
return []
|
14
28
|
end
|
@@ -26,12 +40,18 @@ module Mudguard
|
|
26
40
|
when type?(:class)
|
27
41
|
process_class(node.children, module_name)
|
28
42
|
when type?(:const)
|
29
|
-
[
|
43
|
+
[create_dependency(module_name, node)]
|
30
44
|
else
|
31
45
|
ignore_and_continue(node, module_name)
|
32
46
|
end
|
33
47
|
end
|
34
48
|
|
49
|
+
def create_dependency(module_name, node)
|
50
|
+
dependency = "#{module_name}->#{find_const_name(node.children)}"
|
51
|
+
location = "#{@location}:#{node.location.line}"
|
52
|
+
Dependency.new(location: location, dependency: dependency)
|
53
|
+
end
|
54
|
+
|
35
55
|
def ignore_and_continue(node, module_name)
|
36
56
|
case node
|
37
57
|
when children?
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "mudguard/application/application"
|
5
|
+
require_relative "notification_adapter"
|
6
|
+
|
7
|
+
module Mudguard
|
8
|
+
module Infrastructure
|
9
|
+
module Cli
|
10
|
+
# Parses the cli arguments
|
11
|
+
class Controller
|
12
|
+
def initialize(view:)
|
13
|
+
@view = view
|
14
|
+
@done = false
|
15
|
+
@parser = ::OptionParser.new do |opts|
|
16
|
+
opts.banner = "Usage: mudguard [options] [directory]"
|
17
|
+
opts.on("-h", "--help", "Prints this help") do
|
18
|
+
view.print(opts.to_s)
|
19
|
+
@done = true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse!(argv)
|
25
|
+
directories = @parser.parse!(argv)
|
26
|
+
|
27
|
+
return true if @done
|
28
|
+
|
29
|
+
notification = NotificationAdapter.new(view: @view)
|
30
|
+
directories = [Dir.pwd] if directories.empty?
|
31
|
+
directories.all? { |d| Mudguard::Application.check(d, notification) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mudguard
|
4
|
+
module Infrastructure
|
5
|
+
module Cli
|
6
|
+
# Forwards Notification to the view for printing
|
7
|
+
class NotificationAdapter
|
8
|
+
def initialize(view:)
|
9
|
+
@view = view
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(text)
|
13
|
+
@view.print(text)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../../domain/policies"
|
4
|
+
require_relative "../../domain/error"
|
5
|
+
|
6
|
+
module Mudguard
|
7
|
+
module Infrastructure
|
8
|
+
module Persistence
|
9
|
+
# A file containing the Mudguard-Policies
|
10
|
+
class PolicyFile
|
11
|
+
def self.read(policy_file)
|
12
|
+
policy_exists = File.exist?(policy_file)
|
13
|
+
|
14
|
+
unless policy_exists
|
15
|
+
raise Mudguard::Domain::Error, "expected policy file #{policy_file} doesn't exists"
|
16
|
+
end
|
17
|
+
|
18
|
+
Mudguard::Domain::Policies.new(policies: File.readlines(policy_file))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "mudguard/domain/source"
|
4
|
+
|
5
|
+
module Mudguard
|
6
|
+
module Infrastructure
|
7
|
+
module Persistence
|
8
|
+
# Provides access to all ruby-files of a project
|
9
|
+
class RubyFiles
|
10
|
+
class << self
|
11
|
+
def all(project_path)
|
12
|
+
project_exists = Dir.exist?(project_path)
|
13
|
+
|
14
|
+
unless project_exists
|
15
|
+
raise Mudguard::Domain::Error, "expected project #{project_path} doesn't exists"
|
16
|
+
end
|
17
|
+
|
18
|
+
enumerate_files(project_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def enumerate_files(project_path)
|
24
|
+
project_path_name = Pathname.new(project_path)
|
25
|
+
ruby_files = File.join(project_path, "**", "*.rb")
|
26
|
+
Dir.glob(ruby_files).map do |f|
|
27
|
+
file_path_name = Pathname.new(f)
|
28
|
+
diff_path = file_path_name.relative_path_from(project_path_name).to_s
|
29
|
+
Mudguard::Domain::Source.new(location: File.join("./", diff_path), code: File.read(f))
|
30
|
+
end.lazy
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/mudguard/version.rb
CHANGED
data/lib/mudguard.rb
CHANGED
@@ -1,19 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative "mudguard/
|
5
|
-
require_relative "mudguard/ruby_files"
|
6
|
-
|
7
|
-
# Contains methods to check if your project is a bit muddy
|
8
|
-
module Mudguard
|
9
|
-
class << self
|
10
|
-
def check(project_path)
|
11
|
-
policy_file_path = File.expand_path("MudguardFile", project_path)
|
12
|
-
policies = PolicyFile.read(policy_file_path)
|
13
|
-
|
14
|
-
files = RubyFiles.all(project_path).map { |f| File.read(f) }
|
15
|
-
|
16
|
-
policies.check(files)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
3
|
+
require_relative "./mudguard/version"
|
4
|
+
require_relative "./mudguard/application/application"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mudguard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jorg Jenni
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -171,13 +171,17 @@ files:
|
|
171
171
|
- Rakefile
|
172
172
|
- exe/mudguard
|
173
173
|
- lib/mudguard.rb
|
174
|
-
- lib/mudguard/
|
175
|
-
- lib/mudguard/
|
176
|
-
- lib/mudguard/
|
177
|
-
- lib/mudguard/
|
178
|
-
- lib/mudguard/
|
174
|
+
- lib/mudguard/application/application.rb
|
175
|
+
- lib/mudguard/domain/dependency.rb
|
176
|
+
- lib/mudguard/domain/error.rb
|
177
|
+
- lib/mudguard/domain/policies.rb
|
178
|
+
- lib/mudguard/domain/source.rb
|
179
|
+
- lib/mudguard/infrastructure/cli/controller.rb
|
180
|
+
- lib/mudguard/infrastructure/cli/notification_adapter.rb
|
181
|
+
- lib/mudguard/infrastructure/cli/view.rb
|
182
|
+
- lib/mudguard/infrastructure/persistence/policy_file.rb
|
183
|
+
- lib/mudguard/infrastructure/persistence/ruby_files.rb
|
179
184
|
- lib/mudguard/version.rb
|
180
|
-
- lib/tasks/gem.rake
|
181
185
|
- lib/tasks/rubocop.rake
|
182
186
|
- lib/tasks/test.rake
|
183
187
|
- mudguard.gemspec
|
data/lib/mudguard/policies.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "ruby_analyser"
|
4
|
-
|
5
|
-
module Mudguard
|
6
|
-
# Contains the policies to be enforced
|
7
|
-
class Policies
|
8
|
-
def initialize(policies: [])
|
9
|
-
@policies = policies.map { |l| l.gsub(/\s/, "") }.map { |p| /^#{p}/ }
|
10
|
-
end
|
11
|
-
|
12
|
-
def check(sources)
|
13
|
-
sources.all? do |source|
|
14
|
-
dependencies = RubyAnalyser.find_mod_dependencies(source)
|
15
|
-
dependencies.all? do |d|
|
16
|
-
@policies.any? do |p|
|
17
|
-
d.match?(p)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/mudguard/policy_file.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "policies"
|
4
|
-
require_relative "error"
|
5
|
-
|
6
|
-
module Mudguard
|
7
|
-
# A file containing the Mudguard-Policies
|
8
|
-
class PolicyFile
|
9
|
-
def self.read(policy_file)
|
10
|
-
policy_exists = File.exist?(policy_file)
|
11
|
-
|
12
|
-
raise Error, "expected policy file #{policy_file} doesn't exists" unless policy_exists
|
13
|
-
|
14
|
-
Policies.new(policies: File.readlines(policy_file))
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/mudguard/ruby_files.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mudguard
|
4
|
-
# Provides access to all ruby-files of a project
|
5
|
-
class RubyFiles
|
6
|
-
class << self
|
7
|
-
def all(project_path)
|
8
|
-
project_exists = Dir.exist?(project_path)
|
9
|
-
|
10
|
-
raise Error, "expected project #{project_path} doesn't exists" unless project_exists
|
11
|
-
|
12
|
-
ruby_files = File.join(project_path, "**", "*.rb")
|
13
|
-
Dir.glob(ruby_files).lazy
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/tasks/gem.rake
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "rspec/core/rake_task"
|
4
|
-
require "mudguard/version"
|
5
|
-
|
6
|
-
namespace :gem do
|
7
|
-
desc "Publishes the gem on rubygems.org"
|
8
|
-
task publish: "gem:build" do
|
9
|
-
exec("gem push mudguard-#{Mudguard::VERSION}.gem")
|
10
|
-
end
|
11
|
-
desc "Builds the gem"
|
12
|
-
task :build do
|
13
|
-
exec("gem build mudguard.gemspec")
|
14
|
-
end
|
15
|
-
end
|