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.
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