forked from phpeterson-usf/autograder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
grade
executable file
·114 lines (95 loc) · 3.59 KB
/
grade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env python3
import json
import os
from pathlib import Path
from actions.cmd import *
from actions.util import *
from actions.canvas import Canvas, CanvasMapper
from actions.config import Args, Config
from actions.git import Git
from actions.test import Test
class Repo:
def __init__(self, project, **kwargs):
self.student = kwargs.get('student')
if self.student:
pg = make_repo_path(project, self.student)
self.local = os.path.join('.', pg)
else:
self.local = kwargs.get('local')
self.label = self.local.split('/')[-1]
# Reconstitute 'grade class' results from previously-saved file
# This allows long-running test cases to be factored out
# of the upload process, which can also take some time
def upload_class(cfg, args):
path = Path(args.project + '.json')
if not path.exists():
fatal(f'{path} does not exist. Run "grade class -p {args.project}" first')
with open(path) as f:
data = f.read()
class_results = json.loads(data)
canvas = Canvas.from_cfg(cfg.Canvas, args)
mapper = CanvasMapper.from_cfg(cfg.CanvasMapper)
for result in class_results:
# Map GitHub username to Canvas SIS Login ID using imported CSV file
login_id = mapper.lookup(result['student'])
canvas.add_score(login_id, result['score'], result['comment'])
canvas.upload()
def main():
cfg = Config.from_file()
args = Args.from_cmdline()
if args.action == 'upload':
upload_class(cfg, args)
return 0
tester = Test.from_cfg(cfg.Test, args)
git = Git.from_cfg(cfg.Git, args)
# Build list of repos to run, either from '.' or list of students
repos = []
if args.action == 'test':
repo = Repo(args.project, local='.')
repos.append(repo)
else:
students = cfg.Config.students # old way
if not students:
mapper = CanvasMapper.from_cfg(cfg.CanvasMapper)
students = mapper.get_github_list() # new way
if not students:
fatal(f"Must either 'test' one repo or give a list of students in {Config.path}")
# Make repo list from student list
for s in students:
repo = Repo(args.project, student=s)
repos.append(repo)
# Calc column width for justified printing
longest = 0
for r in repos:
l = len(r.local)
if l > longest:
longest = l
longest += 1
# Run the specified actions for all of the repos
class_results = []
for repo in repos:
print_justified(repo.local, longest)
try:
if args.action == 'clone':
git.clone(repo.student)
elif args.action == 'pull':
git.pull(repo.student)
elif args.action == 'exec':
output = cmd_exec_capture(args.exec_cmd, wd=repo.local, shell=True)
print(output)
elif args.action == 'class' or args.action == 'test':
repo_results = tester.test(repo.student, repo.local)
if args.action == 'class':
class_results.append(repo_results)
except Exception as e:
print_red(repo.label + ' ' + str(e), '\n')
continue
if args.action == 'class':
# Summary by score frequency
tester.print_histogram(class_results)
# Write test results out to temp file for later upload
class_json = json.dumps(class_results, indent=4, sort_keys=True)
with open(args.project + '.json', 'w') as f:
f.write(class_json)
if __name__ == "__main__":
main()