taeval 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +6 -0
  6. data/Gemfile +7 -0
  7. data/Gemfile.lock +37 -0
  8. data/LICENSE +201 -0
  9. data/README.md +36 -0
  10. data/Rakefile +31 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/bin/taeval +9 -0
  14. data/config/config.yml +27 -0
  15. data/config/hadolint.yml +10 -0
  16. data/config/plagium.yml +12 -0
  17. data/config/report.csv +0 -0
  18. data/config/students.csv +4 -0
  19. data/config/taeval +11 -0
  20. data/config/unittest.yml +8 -0
  21. data/lib/taeval.rb +27 -0
  22. data/lib/taeval/cli.rb +26 -0
  23. data/lib/taeval/config_manager.rb +33 -0
  24. data/lib/taeval/executor.rb +29 -0
  25. data/lib/taeval/file_helper.rb +40 -0
  26. data/lib/taeval/git_checkout/bitbucket_repo.rb +74 -0
  27. data/lib/taeval/git_checkout/config.rb +35 -0
  28. data/lib/taeval/git_checkout/github_repo.rb +65 -0
  29. data/lib/taeval/git_checkout/gitlab_repo.rb +86 -0
  30. data/lib/taeval/git_checkout/repo_factory.rb +25 -0
  31. data/lib/taeval/git_checkout/runner.rb +40 -0
  32. data/lib/taeval/hadolint/config.rb +23 -0
  33. data/lib/taeval/hadolint/runner.rb +29 -0
  34. data/lib/taeval/output.rb +17 -0
  35. data/lib/taeval/plagium/config.rb +28 -0
  36. data/lib/taeval/plagium/runner.rb +46 -0
  37. data/lib/taeval/reporter.rb +27 -0
  38. data/lib/taeval/runner_factory.rb +29 -0
  39. data/lib/taeval/runner_wrapper.rb +14 -0
  40. data/lib/taeval/static_code_analysis/runner.rb +15 -0
  41. data/lib/taeval/unittest/config.rb +21 -0
  42. data/lib/taeval/unittest/runner.rb +59 -0
  43. data/lib/taeval/version.rb +3 -0
  44. data/taeval.gemspec +36 -0
  45. metadata +147 -0
File without changes
@@ -0,0 +1,4 @@
1
+ Gips Jakab; neptuncode1; github; gipszjakab; repo-or-hw-gipsz-jakab
2
+ John Doe; neptuncode2; gitlab; johndoe; repo-or-hw-doe-john
3
+ Thomas Muller; neptuncode3; bitbucket; thomasmuller; repo-or-hw-thomas-muller
4
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'taeval'
4
+
5
+ Taeval.eval 'config.yml' do
6
+ run :git_checkout
7
+ run :plagium
8
+ run :unittest
9
+ run :hadolint
10
+ end
11
+
@@ -0,0 +1,8 @@
1
+ ---
2
+
3
+ build:
4
+ tool: gradle
5
+ cmd: gradle test
6
+ original: obudai-nagyv-20-original
7
+
8
+
@@ -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
@@ -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