taeval 0.2.2
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 +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
|