brown_noser 0.2.0 → 0.2.1
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 +4 -4
- data/README.md +11 -0
- data/lib/brown_noser/version.rb +1 -1
- data/lib/brown_noser.rb +7 -6
- data/lib/cheating_detection.rb +19 -59
- data/lib/pull_branch_file_extractor.rb +61 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e40fcf62cf35b124491ebfad296fef3b965c5564
|
4
|
+
data.tar.gz: c11e0646be3988b06ad3e84d678e59c9476e6f66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 687cc3f565935ce35417393bdc934f82e1c7efdf51a213f32548221d946a5135e98b573670cdc68ddbf1c99a966b392cbc2eb74228c673b3dddd3d2d7efe5a42
|
7
|
+
data.tar.gz: bb245d3eacfa69702a442f7cb2d53091ee27645e51c8f2729f782bbba68358374837b70ac45f0bfd37e8d089387482d637f1eca86421e54ad9352dd015100a51
|
data/README.md
CHANGED
@@ -43,6 +43,17 @@ pet -f 'Your query or Regex'
|
|
43
43
|
pet --find 'Your query or Regex'
|
44
44
|
```
|
45
45
|
|
46
|
+
### Detect with Cheating through MOSS
|
47
|
+
Currently supports .cpp files only more coming soon
|
48
|
+
```
|
49
|
+
pet <user> <repo> -u <username> -p <password> -c <moss_id>
|
50
|
+
```
|
51
|
+
The resulting `brown_noser.html` will include a link so you can view the comparisons that MOSS detected as possible duplication.
|
52
|
+
|
53
|
+
##### Create a moss account so you can have a moss_id
|
54
|
+
Visit [https://theory.stanford.edu/~aiken/moss/](https://theory.stanford.edu/~aiken/moss/) and follow the instructions listed under `Registering for MOSS`.
|
55
|
+
Once you send your registration email you will receive a response containing a bunch of perl code. Search the email for `userid`, your MOSS ID will look like this 11111927.
|
56
|
+
|
46
57
|
## Development
|
47
58
|
|
48
59
|
Clone and run `bundle install` to receive deps.
|
data/lib/brown_noser/version.rb
CHANGED
data/lib/brown_noser.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'optparse'
|
2
|
-
autoload :ClientResolver,
|
3
|
-
autoload :ProjectRepoSync,
|
4
|
-
autoload :ProjectRepoSearcher,
|
5
|
-
autoload :CheatingDetection,
|
6
|
-
autoload :PullBranchLister,
|
2
|
+
autoload :ClientResolver, File.expand_path(File.dirname(__FILE__)) + '/client_resolver.rb'
|
3
|
+
autoload :ProjectRepoSync, File.expand_path(File.dirname(__FILE__)) + '/project_repo_sync.rb'
|
4
|
+
autoload :ProjectRepoSearcher, File.expand_path(File.dirname(__FILE__)) + '/project_repo_searcher.rb'
|
5
|
+
autoload :CheatingDetection, File.expand_path(File.dirname(__FILE__)) + '/cheating_detection.rb'
|
6
|
+
autoload :PullBranchLister, File.expand_path(File.dirname(__FILE__)) + '/pull_branch_lister.rb'
|
7
|
+
autoload :PullBranchFileExtractor, File.expand_path(File.dirname(__FILE__)) + '/pull_branch_file_extractor.rb'
|
7
8
|
|
8
9
|
class BrownNoser
|
9
10
|
attr_reader :options
|
@@ -42,7 +43,7 @@ class BrownNoser
|
|
42
43
|
searcher = ProjectRepoSearcher.new.search find
|
43
44
|
elsif cheat
|
44
45
|
puts "CHEAT"
|
45
|
-
cheat_detection = CheatingDetection.new(ARGV[0], ARGV[1], cheat).detect
|
46
|
+
cheat_detection = CheatingDetection.new(ARGV[0], ARGV[1], {moss_id: cheat}).detect
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
data/lib/cheating_detection.rb
CHANGED
@@ -3,87 +3,47 @@ require 'fileutils'
|
|
3
3
|
|
4
4
|
class CheatingDetection
|
5
5
|
|
6
|
+
MOSS_LOGGER_CALLBACK = ->(message=""){puts message}
|
6
7
|
TEMP_DIR = 'brown_noser_cheat_detection'
|
7
8
|
|
8
|
-
def initialize(user, repo,
|
9
|
+
def initialize(user, repo, moss_options={})
|
9
10
|
@user = user
|
10
11
|
@repo = repo
|
11
|
-
@moss_id = moss_id
|
12
|
-
end
|
13
|
-
|
14
|
-
def detect
|
15
|
-
pull_details = PullBranchLister.new(@user, @repo).list
|
16
|
-
|
17
|
-
recreate_tmp_dir
|
18
|
-
|
19
|
-
commands = pull_details.map &command_orgnaizer()
|
20
|
-
|
21
|
-
commands.flatten.each do |command|
|
22
|
-
prepared_command = command.call
|
23
|
-
puts prepared_command unless prepared_command.empty?
|
24
|
-
`#{prepared_command}` unless prepared_command.empty?
|
25
|
-
end
|
12
|
+
@moss_id = moss_options.fetch(:moss_id, 000000000)
|
26
13
|
|
27
14
|
# Create the MossRuby object
|
28
15
|
@moss ||= MossRuby.new(@moss_id) #replace 000000000 with your user id
|
29
16
|
|
30
17
|
# Set options -- the options will already have these default values
|
31
|
-
@moss.options[:max_matches]
|
32
|
-
@moss.options[:directory_submission] =
|
33
|
-
@moss.options[:show_num_matches]
|
34
|
-
@moss.options[:experimental_server]
|
35
|
-
@moss.options[:comment]
|
36
|
-
@moss.options[:language]
|
18
|
+
@moss.options[:max_matches] = moss_options.fetch(:max_matches, 10)
|
19
|
+
@moss.options[:directory_submission] = moss_options.fetch(:directory_submission, false)
|
20
|
+
@moss.options[:show_num_matches] = moss_options.fetch(:show_num_matches, 250)
|
21
|
+
@moss.options[:experimental_server] = moss_options.fetch(:experimental_server, false)
|
22
|
+
@moss.options[:comment] = moss_options.fetch(:comment, '')
|
23
|
+
@moss.options[:language] = moss_options.fetch(:comment, 'cc')
|
24
|
+
end
|
25
|
+
|
26
|
+
def detect
|
27
|
+
pull_details = PullBranchLister.new(@user, @repo).list
|
28
|
+
extractor = PullBranchFileExtractor.new(TEMP_DIR, pull_details)
|
29
|
+
extractor.extract
|
37
30
|
|
38
31
|
# Create a file hash, with the files to be processed
|
39
32
|
to_check = MossRuby.empty_file_hash
|
40
|
-
|
41
|
-
MossRuby.add_file(to_check,
|
33
|
+
files_to_check = Dir.glob("#{TEMP_DIR}/**/*").select { |f| f =~ /\.(h|cpp)$/ }
|
34
|
+
MossRuby.add_file(to_check, files_to_check)
|
42
35
|
|
43
36
|
# Get server to process files
|
44
|
-
url = @moss.check to_check
|
37
|
+
url = @moss.check to_check, MOSS_LOGGER_CALLBACK
|
45
38
|
|
46
39
|
IO.write "brown_noser.html", "<div><h3>Cheat Detection Results</h3><br/><a href='#{url}'>#{url}</a></div>"
|
47
|
-
|
40
|
+
extractor.cleanup
|
48
41
|
|
49
42
|
# Get results
|
50
43
|
results = @moss.extract_results url
|
51
44
|
end
|
52
45
|
|
53
46
|
private
|
54
|
-
def make_folder_for_branch(user, branch)
|
55
|
-
->(){ FileUtils.mkdir_p("#{TEMP_DIR}/#{user}_#{branch}") }
|
56
|
-
end
|
57
|
-
|
58
|
-
def copy_file(source, dest)
|
59
|
-
->(){ "cp \"#{source}\" \"#{dest}\"" }
|
60
|
-
end
|
61
|
-
|
62
|
-
def extract_source_files(user, branch, dest_folder)
|
63
|
-
->(){
|
64
|
-
files = `git ls-tree --full-name --name-only -r #{user}/#{branch} | grep '.h$\\|.cpp$'`.split("\n")
|
65
|
-
copy_files = files.map do |file|
|
66
|
-
copy_file(file, "#{dest_folder}/#{file}").call
|
67
|
-
end
|
68
|
-
copy_files.join(" && ")
|
69
|
-
}
|
70
|
-
end
|
71
|
-
|
72
|
-
def recreate_tmp_dir
|
73
|
-
FileUtils.rm_rf TEMP_DIR
|
74
|
-
FileUtils.mkdir TEMP_DIR
|
75
|
-
end
|
76
|
-
|
77
|
-
def command_orgnaizer
|
78
|
-
->(pull_context){
|
79
|
-
[
|
80
|
-
make_folder_for_branch(pull_context[0], pull_context[1]),
|
81
|
-
ProjectRepoSync::git_checkout("#{pull_context[0]}/#{pull_context[1]}"),
|
82
|
-
extract_source_files(pull_context[0], pull_context[1], "#{TEMP_DIR}/#{pull_context[0]}_#{pull_context[1]}")
|
83
|
-
]
|
84
|
-
}
|
85
|
-
end
|
86
|
-
|
87
47
|
def extract_results
|
88
48
|
results.each_with_index { |match, i|
|
89
49
|
match.each { |file|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class PullBranchFileExtractor
|
2
|
+
def initialize(temp_dir, pull_details)
|
3
|
+
@temp_dir = temp_dir
|
4
|
+
@pull_details = pull_details
|
5
|
+
end
|
6
|
+
|
7
|
+
def extract
|
8
|
+
clean_tmp_dir
|
9
|
+
create_tmp_dir
|
10
|
+
|
11
|
+
commands = @pull_details.map &command_orgnaizer()
|
12
|
+
|
13
|
+
commands.flatten.each do |command|
|
14
|
+
prepared_command = command.call
|
15
|
+
puts prepared_command unless prepared_command.empty?
|
16
|
+
`#{prepared_command}` unless prepared_command.empty?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cleanup
|
21
|
+
clean_tmp_dir
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_tmp_dir
|
27
|
+
FileUtils.mkdir @temp_dir
|
28
|
+
end
|
29
|
+
|
30
|
+
def clean_tmp_dir
|
31
|
+
FileUtils.rm_rf @temp_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
def make_folder_for_branch(user, branch)
|
35
|
+
->(){ FileUtils.mkdir_p("#{@temp_dir}/#{user}_#{branch}") }
|
36
|
+
end
|
37
|
+
|
38
|
+
def copy_file(source, dest)
|
39
|
+
->(){ "cp \"#{source}\" \"#{dest}\"" }
|
40
|
+
end
|
41
|
+
|
42
|
+
def extract_source_files(user, branch, dest_folder)
|
43
|
+
->(){
|
44
|
+
files = `git ls-tree --full-name --name-only -r #{user}/#{branch} | grep '\.h$\\|\.cpp$'`.split("\n")
|
45
|
+
copy_files = files.map do |file|
|
46
|
+
copy_file(file, "#{dest_folder}/#{file}").call
|
47
|
+
end
|
48
|
+
copy_files.join(" && ")
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def command_orgnaizer
|
53
|
+
->(pull_context){
|
54
|
+
[
|
55
|
+
make_folder_for_branch(pull_context[0], pull_context[1]),
|
56
|
+
ProjectRepoSync::git_checkout("#{pull_context[0]}/#{pull_context[1]}"),
|
57
|
+
extract_source_files(pull_context[0], pull_context[1], "#{@temp_dir}/#{pull_context[0]}_#{pull_context[1]}")
|
58
|
+
]
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brown_noser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Scarrone
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- lib/client_resolver.rb
|
89
89
|
- lib/project_repo_searcher.rb
|
90
90
|
- lib/project_repo_sync.rb
|
91
|
+
- lib/pull_branch_file_extractor.rb
|
91
92
|
- lib/pull_branch_lister.rb
|
92
93
|
homepage: https://github.com/WCCCEDU/github_grading_tools_rb
|
93
94
|
licenses:
|