taeval 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +37 -0
- data/LICENSE +201 -0
- data/README.md +36 -0
- data/Rakefile +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/taeval +9 -0
- data/config/config.yml +27 -0
- data/config/hadolint.yml +10 -0
- data/config/plagium.yml +12 -0
- data/config/report.csv +0 -0
- data/config/students.csv +4 -0
- data/config/taeval +11 -0
- data/config/unittest.yml +8 -0
- data/lib/taeval.rb +27 -0
- data/lib/taeval/cli.rb +26 -0
- data/lib/taeval/config_manager.rb +33 -0
- data/lib/taeval/executor.rb +29 -0
- data/lib/taeval/file_helper.rb +40 -0
- data/lib/taeval/git_checkout/bitbucket_repo.rb +74 -0
- data/lib/taeval/git_checkout/config.rb +35 -0
- data/lib/taeval/git_checkout/github_repo.rb +65 -0
- data/lib/taeval/git_checkout/gitlab_repo.rb +86 -0
- data/lib/taeval/git_checkout/repo_factory.rb +25 -0
- data/lib/taeval/git_checkout/runner.rb +40 -0
- data/lib/taeval/hadolint/config.rb +23 -0
- data/lib/taeval/hadolint/runner.rb +29 -0
- data/lib/taeval/output.rb +17 -0
- data/lib/taeval/plagium/config.rb +28 -0
- data/lib/taeval/plagium/runner.rb +46 -0
- data/lib/taeval/reporter.rb +27 -0
- data/lib/taeval/runner_factory.rb +29 -0
- data/lib/taeval/runner_wrapper.rb +14 -0
- data/lib/taeval/static_code_analysis/runner.rb +15 -0
- data/lib/taeval/unittest/config.rb +21 -0
- data/lib/taeval/unittest/runner.rb +59 -0
- data/lib/taeval/version.rb +3 -0
- data/taeval.gemspec +36 -0
- metadata +147 -0
data/config/report.csv
ADDED
File without changes
|
data/config/students.csv
ADDED
data/config/taeval
ADDED
data/config/unittest.yml
ADDED
data/lib/taeval.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
require 'taeval/cli'
|
3
|
+
|
4
|
+
require "taeval/version"
|
5
|
+
require 'taeval/runner_wrapper'
|
6
|
+
require 'taeval/config_manager'
|
7
|
+
require 'taeval/executor'
|
8
|
+
|
9
|
+
module Taeval
|
10
|
+
|
11
|
+
def self.eval(config_file, &block)
|
12
|
+
config_manager = ConfigManager.create(config_file)
|
13
|
+
reporter = config_manager.reporter
|
14
|
+
config = config_manager.config
|
15
|
+
output = config_manager.output
|
16
|
+
executor = Executor.new(config, output, reporter)
|
17
|
+
|
18
|
+
runner = RunnerWrapper.new(executor)
|
19
|
+
runner.instance_eval &block
|
20
|
+
|
21
|
+
executor.run
|
22
|
+
reporter.save
|
23
|
+
rescue StandardError => e
|
24
|
+
puts "\e[31mError:\e[0m #{ e.message }"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/taeval/cli.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
module Taeval
|
3
|
+
module CLI
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def parse_options(options = ARGV)
|
8
|
+
if options.size != 1 || options.first != 'init'
|
9
|
+
raise "Argument must be init! Use `taeval init` to initialize project."
|
10
|
+
end
|
11
|
+
options
|
12
|
+
end
|
13
|
+
|
14
|
+
def start(opts)
|
15
|
+
puts "Initialize configuration ..."
|
16
|
+
dest = Dir.pwd
|
17
|
+
path = File.join(File.dirname(File.expand_path(__FILE__)), '../../config')
|
18
|
+
config_files = Dir.glob("#{path}/*")
|
19
|
+
|
20
|
+
config_files.each do |conf|
|
21
|
+
FileUtils.cp(conf, dest)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
require 'taeval/reporter'
|
4
|
+
require 'taeval/output'
|
5
|
+
require 'taeval/file_helper'
|
6
|
+
|
7
|
+
module Taeval
|
8
|
+
class ConfigManager
|
9
|
+
extend Taeval::FileHelper
|
10
|
+
|
11
|
+
attr_reader :config, :output, :reporter
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
def create(config_file)
|
16
|
+
path = path_of(config_file)
|
17
|
+
conf = YAML.load(File.read(path))
|
18
|
+
flatten_include!(conf)
|
19
|
+
ConfigManager.new(conf, Output.new(conf), Reporter.new(conf))
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def initialize(config, output, reporter)
|
27
|
+
@config = config
|
28
|
+
@reporter = reporter
|
29
|
+
@output = output
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require 'taeval/runner_factory'
|
3
|
+
|
4
|
+
module Taeval
|
5
|
+
class Executor
|
6
|
+
include Taeval::FileHelper
|
7
|
+
|
8
|
+
def initialize(config, output, reporter)
|
9
|
+
@config = config
|
10
|
+
@reporter = reporter
|
11
|
+
@output = output
|
12
|
+
@runners = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(runner)
|
16
|
+
conf = @config[runner.to_s]
|
17
|
+
['solution', 'report', 'verbose'].each { |key| conf[key] = @config[key] }
|
18
|
+
@runners[runner] = RunnerFactory.create(runner, conf, @output, @reporter)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
@runners.each_pair { |_, runner| runner.run }
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
@reporter.save
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Taeval
|
4
|
+
module FileHelper
|
5
|
+
|
6
|
+
def exist?(file)
|
7
|
+
return true if File.exist?(file)
|
8
|
+
full_path = File.exist?("#{File.dirname(File.expand_path(caller_locations.last.path))}/#{file}")
|
9
|
+
File.exist?(full_path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def path_of(file)
|
13
|
+
return file if File.exist?(file)
|
14
|
+
path = "#{File.dirname(File.expand_path(caller_locations.last.path))}/#{file}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def flatten_include!(conf)
|
18
|
+
conf.each_pair do |k, v|
|
19
|
+
if conf[k].is_a?(Hash) && conf[k].has_key?('include')
|
20
|
+
path = path_of(conf[k]['include'])
|
21
|
+
conf[k] = YAML.load(File.read(path))
|
22
|
+
conf[k].delete('include')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(file, path=nil)
|
28
|
+
if !path.nil? && File.exist?(path) && File.directory?(path)
|
29
|
+
full_path = "#{path}/#{file}"
|
30
|
+
else
|
31
|
+
full_path = "#{File.dirname(File.expand_path(caller_locations.last.path))}/#{file}"
|
32
|
+
end
|
33
|
+
File.new(full_path, 'w')
|
34
|
+
end
|
35
|
+
|
36
|
+
def open(file, path=nil)
|
37
|
+
File.open(file)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
|
2
|
+
module Taeval
|
3
|
+
module GitCheckout
|
4
|
+
class BitbucketRepo
|
5
|
+
|
6
|
+
def initialize(config, output, reporter)
|
7
|
+
@reporter = reporter
|
8
|
+
@output = output
|
9
|
+
|
10
|
+
@id = config[:id]
|
11
|
+
|
12
|
+
@token = config[:token]
|
13
|
+
@user = config[:user]
|
14
|
+
@repo = config[:repo]
|
15
|
+
@branch = config[:branch]
|
16
|
+
@solution = config[:solution]
|
17
|
+
|
18
|
+
@prefix = config[:prefix]
|
19
|
+
@attr = config[:attr]
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate
|
23
|
+
url = "https://api.bitbucket.org/2.0/repositories/#{@user}/#{@repo}"
|
24
|
+
cmd = "curl -sL --user '#{@token}' #{url}"
|
25
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
26
|
+
|
27
|
+
@output.print "validating #{url}", stdout, stderr
|
28
|
+
|
29
|
+
repo_api_data = JSON.parse(stdout, symbolize_names: true)
|
30
|
+
if stderr == '' && !repo_api_data.has_key?(:error)
|
31
|
+
field_validate(repo_api_data)
|
32
|
+
else
|
33
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{stderr}") if stderr != ''
|
34
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{repo_api_data[:error]}; url: #{url}") if repo_api_data.has_key?(:error)
|
35
|
+
end
|
36
|
+
|
37
|
+
cmd = "curl -sL --user '#{@token}' #{url}/forks"
|
38
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
39
|
+
|
40
|
+
@output.print "validating #{url}/forks", stdout, stderr
|
41
|
+
|
42
|
+
repo_api_data = JSON.parse(stdout, symbolize_names: true)
|
43
|
+
if stderr == '' && !repo_api_data.has_key?(:error)
|
44
|
+
fork_validate(repo_api_data)
|
45
|
+
else
|
46
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{stderr}") if stderr != ''
|
47
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{repo_api_data[:error]}; url: #{url}") if repo_api_data.has_key?(:error)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def clone
|
53
|
+
url = "https://#{@token}@bitbucket.org/#{@user}/#{@repo}.git"
|
54
|
+
cmd = "git clone #{url} --branch=#{@branch} #{@solution}/#{@repo}"
|
55
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
56
|
+
|
57
|
+
@output.print "cloning #{url}", stdout, stderr
|
58
|
+
|
59
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "#{status}; #{stderr}") if status != 0
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def field_validate(data)
|
65
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Repo should start with #{@prefix}") if !data[:name].start_with?(@prefix)
|
66
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute is_private should be #{@attr[:private]}") if data[:is_private] != @attr[:private]
|
67
|
+
end
|
68
|
+
|
69
|
+
def fork_validate(data)
|
70
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Fork counts should be 0") if data[:values].size > 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
require 'taeval/file_helper'
|
3
|
+
|
4
|
+
module Taeval
|
5
|
+
module GitCheckout
|
6
|
+
class Config
|
7
|
+
include Taeval::FileHelper
|
8
|
+
|
9
|
+
attr_reader :source, :solution, :attr, :tokens, :prefix, :fork_parent, :branch
|
10
|
+
|
11
|
+
def initialize(conf_h)
|
12
|
+
@tokens = conf_h.fetch('token', '')
|
13
|
+
file = open(path_of(conf_h['source']))
|
14
|
+
@source = file.readlines
|
15
|
+
.map { |line| line.split(';').map(&:strip) }
|
16
|
+
.map { |e| {name: e[0], id: e[1], host: e[2], user: e[3], repo: e[4]} }
|
17
|
+
|
18
|
+
@attr = {}
|
19
|
+
@attr[:private] = conf_h.fetch('private', true)
|
20
|
+
@attr[:fork] = conf_h.fetch('fork', false)
|
21
|
+
@attr[:forks_count] = conf_h.fetch('forks_count', 0).to_i
|
22
|
+
@attr[:fork_parent] = conf_h.fetch('fork_parent', '')
|
23
|
+
|
24
|
+
@branch = conf_h.fetch('branch', 'main')
|
25
|
+
@prefix = conf_h.fetch('prefix', '')
|
26
|
+
|
27
|
+
@solution = path_of(conf_h.dig('solution', 'path'))
|
28
|
+
if !File.exist?(@solution)
|
29
|
+
Dir.mkdir @solution
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
module Taeval
|
3
|
+
module GitCheckout
|
4
|
+
class GithubRepo
|
5
|
+
|
6
|
+
def initialize(config, output, reporter)
|
7
|
+
@reporter = reporter
|
8
|
+
@output = output
|
9
|
+
|
10
|
+
@id = config[:id]
|
11
|
+
|
12
|
+
@token = config[:token]
|
13
|
+
@user = config[:user]
|
14
|
+
@repo = config[:repo]
|
15
|
+
@branch = config[:branch]
|
16
|
+
@solution = config[:solution]
|
17
|
+
|
18
|
+
@prefix = config[:prefix]
|
19
|
+
@attr = config[:attr]
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate
|
23
|
+
url = "https://api.github.com/repos/#{@user}/#{@repo}"
|
24
|
+
cmd = "curl -sL -H 'Authorization: token #{@token}' -H 'Accept: application/vnd.github.v3+json' #{url}"
|
25
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
26
|
+
|
27
|
+
@output.print "validating #{url}", stdout, stderr
|
28
|
+
|
29
|
+
repo_api_data = JSON.parse(stdout, symbolize_names: true)
|
30
|
+
if stderr == '' && !repo_api_data.has_key?(:message)
|
31
|
+
field_validate(repo_api_data)
|
32
|
+
else
|
33
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{stderr}") if stderr != ''
|
34
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{repo_api_data[:message]}; url: #{url}") if repo_api_data.has_key?(:message)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def clone
|
40
|
+
url = "https://#{@user}:#{@token}@github.com/#{@user}/#{@repo}.git"
|
41
|
+
cmd = "git clone #{url} --branch=#{@branch} #{@solution}/#{@repo}"
|
42
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
43
|
+
|
44
|
+
@output.print "cloning #{url}", stdout, stderr
|
45
|
+
|
46
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "#{status}; #{stderr}") if status != 0
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def field_validate(data)
|
52
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Repo should start with #{@prefix}") if !data[:name].start_with?(@prefix)
|
53
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute private should be #{@attr[:private]}") if data[:private] != @attr[:private]
|
54
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute forks_count should be #{@attr[:forks_count]}") if data[:forks_count] != @attr[:forks_count]
|
55
|
+
|
56
|
+
if @attr[:fork]
|
57
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute parent->full_name should be #{@attr[:fork_parent]}") if data.dig(:parent, :full_name) != @attr[:fork_parent]
|
58
|
+
else
|
59
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute parent should be nil (#{data.dig(:parent, :full_name)})") if !data.dig(:parent, :full_name).nil?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
module Taeval
|
3
|
+
module GitCheckout
|
4
|
+
class GitlabRepo
|
5
|
+
|
6
|
+
def initialize(config, output, reporter)
|
7
|
+
@reporter = reporter
|
8
|
+
@output = output
|
9
|
+
|
10
|
+
@id = config[:id]
|
11
|
+
|
12
|
+
@token = config[:token]
|
13
|
+
@user = config[:user]
|
14
|
+
@repo = config[:repo]
|
15
|
+
@branch = config[:branch]
|
16
|
+
@solution = config[:solution]
|
17
|
+
|
18
|
+
@prefix = config[:prefix]
|
19
|
+
@attr = config[:attr]
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate
|
23
|
+
url = "https://gitlab.com/api/v4/projects/#{@user}%2F#{@repo}"
|
24
|
+
cmd = "curl -sL --header 'PRIVATE-TOKEN: #{@token}' #{url}"
|
25
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
26
|
+
|
27
|
+
@output.print "validating #{url}", stdout, stderr
|
28
|
+
|
29
|
+
repo_api_data = JSON.parse(stdout, symbolize_names: true)
|
30
|
+
if stderr == '' && !repo_api_data.has_key?(:message)
|
31
|
+
field_validate(repo_api_data)
|
32
|
+
else
|
33
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{stderr}") if stderr != ''
|
34
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{repo_api_data[:message]}; url: #{url}") if repo_api_data.has_key?(:message)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
cmd = "curl -sL --header 'PRIVATE-TOKEN: #{@token}' #{url}/users"
|
39
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
40
|
+
|
41
|
+
@output.print "validating #{url}/users", stdout, stderr
|
42
|
+
|
43
|
+
repo_api_data = JSON.parse(stdout, symbolize_names: true)
|
44
|
+
if stderr == '' && repo_api_data.is_a?(Array)
|
45
|
+
fork_validate(repo_api_data)
|
46
|
+
else
|
47
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{stderr}") if stderr != ''
|
48
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "status: #{status}; message: #{repo_api_data[:message]}; url: #{url}") if repo_api_data.has_key?(:message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def clone
|
53
|
+
url = "https://oauth2:#{@token}@gitlab.com/#{@user}/#{@repo}.git"
|
54
|
+
cmd = "git clone #{url} --branch=#{@branch} #{@solution}/#{@repo}"
|
55
|
+
stdout, stderr, status = Open3.capture3(cmd)
|
56
|
+
|
57
|
+
@output.print "cloning #{url}", stdout, stderr
|
58
|
+
|
59
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "#{status}; #{stderr}") if status != 0
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def field_validate(data)
|
65
|
+
|
66
|
+
if !data[:path].start_with?(@prefix)
|
67
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Repo should start with #{@prefix}")
|
68
|
+
else
|
69
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute visibility should be private") if data[:visibility] != 'private'
|
70
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute forks_count should be #{@attr[:forks_count]}") if data[:forks_count] != @attr[:forks_count]
|
71
|
+
|
72
|
+
if @attr[:fork]
|
73
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Attribute parent->full_name should be #{@attr[:fork_parent]}") if data.dig(:parent, :full_name) != @attr[:fork_parent]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def fork_validate(data)
|
79
|
+
if data.size > 2
|
80
|
+
@reporter.add(repo: @repo, runner: :git_checkout, msg: "Too many users assigned to the project.")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|