From e1ec86d219dacef6b08580875090dd3ad6d994b1 Mon Sep 17 00:00:00 2001 From: Nuvole Date: Wed, 23 Oct 2024 18:53:41 +0800 Subject: [PATCH] feat: migrate repo & init classes --- .gitignore | 2 +- joj3_config_generator/convert.py | 27 +- joj3_config_generator/lib/__init__.py | 11 + joj3_config_generator/lib/repo.py | 123 ++++ joj3_config_generator/models/result.py | 34 +- joj3_config_generator/models/task.py | 48 +- tests/convert/basic/repo.toml | 2 +- tests/convert/basic/task.json | 814 ++++++++++++++++++++++--- tests/convert/basic/task.toml | 133 +++- tests/immutable_file/.gitattributes | 33 + tests/immutable_file/.gitignore | 23 + tests/immutable_file/push.yaml | 18 + tests/immutable_file/release.yaml | 20 + 13 files changed, 1156 insertions(+), 132 deletions(-) create mode 100644 joj3_config_generator/lib/__init__.py create mode 100644 joj3_config_generator/lib/repo.py create mode 100644 tests/immutable_file/.gitattributes create mode 100644 tests/immutable_file/.gitignore create mode 100644 tests/immutable_file/push.yaml create mode 100644 tests/immutable_file/release.yaml diff --git a/.gitignore b/.gitignore index 6a5b3ae..b832e0e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ dist/ downloads/ eggs/ .eggs/ -lib/ +# lib/ lib64/ parts/ sdist/ diff --git a/joj3_config_generator/convert.py b/joj3_config_generator/convert.py index 9badd5f..96a329a 100644 --- a/joj3_config_generator/convert.py +++ b/joj3_config_generator/convert.py @@ -1,6 +1,20 @@ from typing import List from joj3_config_generator.models import joj1, repo, result, task +from joj3_config_generator.lib.repo import getHealthcheckConfig, getTeapotConfig +from joj3_config_generator.models import ( + Cmd, + CmdFile, + ExecutorConfig, + ExecutorWithConfig, + ParserConfig, + Repo, + ResultConfig, + Stage, + StageConfig, + Task, + TeapotConfig, +) # FIXME: LLM generated convert function, only for demostration @@ -8,7 +22,8 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config: # Create the base ResultConf object result_conf = result.Config( name=task_conf.task, - log_path=f"{task_conf.task.replace(' ', '_')}.log", + # TODO: specify the exact folder difference + log_path=f"{task_conf.task.replace(' ', '-')}.log", expire_unix_timestamp=( int(task_conf.release.deadline.timestamp()) if task_conf.release.deadline @@ -16,8 +31,14 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config: ), stage=result.Stage(stages=[], sandbox_token=repo_conf.sandbox_token), teapot=result.Teapot(), + stage=StageConfig(stages=[], sandbox_token=repo_conf.sandbox_token), + teapot=getTeapotConfig(repo_conf, task_conf), ) + # Construct healthcheck stage + healthcheck_stage = getHealthcheckConfig(repo_conf, task_conf) + result_conf.stage.stages.append(healthcheck_stage) + cached = [] # Convert each stage in the task configuration for task_stage in task_conf.stages: executor_with_config = result.ExecutorWith( @@ -41,12 +62,12 @@ def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config: result.Parser(name=parser, with_={}) for parser in task_stage.parsers ], ) - if "result-detail" in task_stage.parsers: result_detail_parser = next( p for p in conf_stage.parsers if p.name == "result-detail" ) - result_detail_parser.with_.update(task_stage.result_detail) + if task_stage.result_detail is not None: + result_detail_parser.with_.update(task_stage.result_detail) result_conf.stage.stages.append(conf_stage) diff --git a/joj3_config_generator/lib/__init__.py b/joj3_config_generator/lib/__init__.py new file mode 100644 index 0000000..68802d4 --- /dev/null +++ b/joj3_config_generator/lib/__init__.py @@ -0,0 +1,11 @@ +from joj3_config_generator.models.repo import Repo as Repo +from joj3_config_generator.models.result import Cmd as Cmd +from joj3_config_generator.models.result import CmdFile as CmdFile +from joj3_config_generator.models.result import ExecutorConfig as ExecutorConfig +from joj3_config_generator.models.result import ExecutorWithConfig as ExecutorWithConfig +from joj3_config_generator.models.result import ParserConfig as ParserConfig +from joj3_config_generator.models.result import ResultConfig as ResultConfig +from joj3_config_generator.models.result import Stage as Stage +from joj3_config_generator.models.result import StageConfig as StageConfig +from joj3_config_generator.models.result import TeapotConfig as TeapotConfig +from joj3_config_generator.models.task import Task as Task diff --git a/joj3_config_generator/lib/repo.py b/joj3_config_generator/lib/repo.py new file mode 100644 index 0000000..e9a8d33 --- /dev/null +++ b/joj3_config_generator/lib/repo.py @@ -0,0 +1,123 @@ +import hashlib +import os +import tempfile + +from dotenv import load_dotenv + +from joj3_config_generator.models import ( + Cmd, + CmdFile, + ExecutorConfig, + ExecutorWithConfig, + ParserConfig, + Repo, + ResultConfig, + Stage, + StageConfig, + Task, + TeapotConfig, +) + + +def get_temp_directory() -> str: + return tempfile.mkdtemp(prefix="repo-checker-") + + +def getGradingRepoName() -> str: + path = os.path.expanduser("~/.config/teapot/teapot.env") + if os.path.exists(path): + load_dotenv(path) + repo_name = os.environ.get("GITEA_ORG_NAME") + if repo_name is not None: + return f"{repo_name.split('-')[0]}-joj" + return "ece482-joj" + + +def getTeapotConfig(repo_conf: Repo, task_conf: Task) -> TeapotConfig: + teapot = TeapotConfig( + # TODO: fix the log path + log_path=f"{task_conf.task.replace(' ', '-')}-joint-teapot-debug.log", + scoreboard_path=f"{task_conf.task.replace(' ', '-')}-scoreboard.csv", + failed_table_path=f"{task_conf.task.replace(' ', '-')}-failed-table.md", + grading_repo_name=getGradingRepoName(), + ) + return teapot + + +def getHealthcheckCmd(repo_conf: Repo) -> Cmd: + repoSize = repo_conf.max_size + immutable = repo_conf.files.immutable + repo_size = f"-repoSize={str(repoSize)} " + required_files = repo_conf.files.required + + for i, meta in enumerate(required_files): + required_files[i] = f"-meta={meta} " + + immutable_files = f"-checkFileNameList=" + for i, name in enumerate(immutable): + if i == len(immutable) - 1: + immutable_files = immutable_files + name + " " + else: + immutable_files = immutable_files + name + "," + # FIXME: need to make solution and make things easier to edit with global scope + chore = f"/{get_temp_directory}/repo-health-checker -root=. " + args = "" + args = args + chore + args = args + repo_size + for meta in required_files: + args = args + meta + + args = args + get_hash(immutable) + + args = args + immutable_files + + cmd = Cmd( + args=args.split(), + # FIXME: easier to edit within global scope + copy_in={ + f"/{get_temp_directory()}/repo-health-checker": CmdFile( + src=f"/{get_temp_directory()}/repo-health-checker" + ) + }, + ) + return cmd + + +def getHealthcheckConfig(repo_conf: Repo, task_conf: Task) -> Stage: + healthcheck_stage = Stage( + name="healthcheck", + group="", + executor=ExecutorConfig( + name="sandbox", + with_=ExecutorWithConfig(default=getHealthcheckCmd(repo_conf), cases=[]), + ), + parsers=[ParserConfig(name="healthcheck", with_={"score": 0, "comment": ""})], + ) + return healthcheck_stage + + +def calc_sha256sum(file_path: str) -> str: + sha256_hash = hashlib.sha256() + with open(file_path, "rb") as f: + for byte_block in iter(lambda: f.read(65536 * 2), b""): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + + +def get_hash(immutable_files: list[str]) -> str: # input should be a list + file_path = "../immutable_file/" # TODO: change this when things are on the server + immutable_hash = [] + for i, file in enumerate(immutable_files): + immutable_files[i] = file_path + file.rsplit("/", 1)[-1] + + for i, file in enumerate(immutable_files): + immutable_hash.append(calc_sha256sum(file)) + + hash_check = "-checkFileSumList=" + + for i, file in enumerate(immutable_hash): + if i == len(immutable_hash) - 1: + hash_check = hash_check + file + " " + else: + hash_check = hash_check + file + "," + return hash_check diff --git a/joj3_config_generator/models/result.py b/joj3_config_generator/models/result.py index ab11d99..f084987 100644 --- a/joj3_config_generator/models/result.py +++ b/joj3_config_generator/models/result.py @@ -9,7 +9,7 @@ class CmdFile(BaseModel): content: Optional[str] = None file_id: Optional[str] = Field(None, serialization_alias="fileId") name: Optional[str] = None - max: Optional[int] = None + max: Optional[int] = 4 * 1024 * 1024 symlink: Optional[str] = None stream_in: bool = Field(False, serialization_alias="streamIn") stream_out: bool = Field(False, serialization_alias="streamOut") @@ -17,17 +17,17 @@ class CmdFile(BaseModel): class Cmd(BaseModel): - args: List[str] - env: List[str] = [] - stdin: Optional[CmdFile] = None - stdout: Optional[CmdFile] = None - stderr: Optional[CmdFile] = None - cpu_limit: int = Field(0, serialization_alias="cpuLimit") + args: list[str] + env: list[str] = ["PATH=/usr/bin:/bin:/usr/local/bin"] + stdin: Optional[CmdFile] = CmdFile(content="") + stdout: Optional[CmdFile] = CmdFile(name="stdout", max=4 * 1024) + stderr: Optional[CmdFile] = CmdFile(name="stderr", max=4 * 1024) + cpu_limit: int = Field(4 * 1000000000, serialization_alias="cpuLimit") real_cpu_limit: int = Field(0, serialization_alias="realCpuLimit") - clock_limit: int = Field(0, serialization_alias="clockLimit") - memory_limit: int = Field(0, serialization_alias="memoryLimit") + clock_limit: int = Field(8 * 1000000000, serialization_alias="clockLimit") + memory_limit: int = Field(4 * 1024 * 1024, serialization_alias="memoryLimit") stack_limit: int = Field(0, serialization_alias="stackLimit") - proc_limit: int = Field(0, serialization_alias="procLimit") + proc_limit: int = Field(50, serialization_alias="procLimit") cpu_rate_limit: int = Field(0, serialization_alias="cpuRateLimit") cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit") copy_in: Dict[str, CmdFile] = Field({}, serialization_alias="copyIn") @@ -44,17 +44,19 @@ class Cmd(BaseModel): class OptionalCmd(BaseModel): - args: Optional[List[str]] = None - env: Optional[List[str]] = None + args: Optional[list[str]] = None + env: Optional[list[str]] = ["PATH=/usr/bin:/bin:/usr/local/bin"] stdin: Optional[CmdFile] = None stdout: Optional[CmdFile] = None stderr: Optional[CmdFile] = None - cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit") + cpu_limit: Optional[int] = Field(4 * 1000000000, serialization_alias="cpuLimit") real_cpu_limit: Optional[int] = Field(None, serialization_alias="realCpuLimit") - clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit") - memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit") + clock_limit: Optional[int] = Field(8 * 1000000000, serialization_alias="clockLimit") + memory_limit: Optional[int] = Field( + 4 * 1024 * 1024, serialization_alias="memoryLimit" + ) stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit") - proc_limit: Optional[int] = Field(None, serialization_alias="procLimit") + proc_limit: Optional[int] = Field(50, serialization_alias="procLimit") cpu_rate_limit: Optional[int] = Field(None, serialization_alias="cpuRateLimit") cpu_set_limit: Optional[str] = Field(None, serialization_alias="cpuSetLimit") copy_in: Optional[Dict[str, CmdFile]] = Field(None, serialization_alias="copyIn") diff --git a/joj3_config_generator/models/task.py b/joj3_config_generator/models/task.py index 09a37fc..cf2628f 100644 --- a/joj3_config_generator/models/task.py +++ b/joj3_config_generator/models/task.py @@ -5,26 +5,50 @@ from pydantic import BaseModel, Field class ParserResultDetail(BaseModel): - time: bool = True # Display run time - mem: bool = True # Display memory usage - stdout: bool = False # Display stdout messages - stderr: bool = False # Display stderr messages + time: Optional[bool] = True # Display run time + mem: Optional[bool] = True # Display memory usage + stdout: Optional[bool] = False # Display stdout messages + stderr: Optional[bool] = False # Display stderr messages + exitstatus: Optional[bool] = False + + +class ParserDummy(BaseModel): + comment: Optional[str] = "" + + +class ParserKeyword(BaseModel): + keyword: Optional[list[str]] = None + weight: Optional[list[int]] = None class Files(BaseModel): - import_: List[str] = Field(serialization_alias="import", validation_alias="import") - export: List[str] + import_: Optional[List[str]] = Field(serialization_alias="import", validation_alias="import") + export: Optional[List[str]] + + + +class Limit(BaseModel): + mem: Optional[int] = 4 + cpu: Optional[int] = 4 + stderr: Optional[int] = 4 + stdout: Optional[int] = 4 class Stage(BaseModel): name: str # Stage name command: str # Command to run - files: Files # Files to import and export - score: int # Score for the task - parsers: List[str] # list of parsers - result_detail: ParserResultDetail = ( - ParserResultDetail() - ) # for result-detail parser + files: Optional[Files] = None + score: Optional[int] = 0 + parsers: list[str] # list of parsers + limit: Optional[Limit] = None + dummy: Optional[ParserDummy] = ParserDummy() + keyword: Optional[ParserKeyword] = ParserKeyword() + clangtidy: Optional[ParserKeyword] = ParserKeyword() + cppcheck: Optional[ParserKeyword] = ParserKeyword() + cpplint: Optional[ParserKeyword] = ParserKeyword() + result_detail: Optional[ParserResultDetail] = Field( + ParserResultDetail(), alias="result-detail" + ) class Release(BaseModel): diff --git a/tests/convert/basic/repo.toml b/tests/convert/basic/repo.toml index f9012cc..c77b9f7 100644 --- a/tests/convert/basic/repo.toml +++ b/tests/convert/basic/repo.toml @@ -7,4 +7,4 @@ sandbox_token = "test" whitelist_patterns = ["*.py", "*.txt", "*.md"] whitelist_file = ".whitelist" required = ["main.py", "README.md"] -immutable = ["config.yaml", "setup.py"] +immutable = [".gitignore", ".gitattributes", "push.yaml", "release.yaml"] diff --git a/tests/convert/basic/task.json b/tests/convert/basic/task.json index 294d15c..ae81205 100644 --- a/tests/convert/basic/task.json +++ b/tests/convert/basic/task.json @@ -1,53 +1,79 @@ { - "name": "hw3 ex5", - "logPath": "hw3_ex5.log", - "expireUnixTimestamp": 1729267140, + "name": "Homework 1 exercise 2", + "logPath": "Homework-1-exercise-2.log", + "expireUnixTimestamp": 1728748740, "stage": { "sandboxExecServer": "172.17.0.1:5051", "sandboxToken": "test", "outputPath": "/tmp/joj3_result.json", "stages": [ { - "name": "judge_base", - "group": "hw3 ex5", + "name": "healthcheck", + "group": "", "executor": { "name": "sandbox", "with": { "default": { "args": [ - "./matlab-joj", - "./h3/ex5.m" + "/tmp/repo-health-checker", + "-root=.", + "-repoSize=50.5", + "-meta=main.py", + "-meta=README.md", + "-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,8d1229900c6fc6711b5cc141d1ab5ea7f5b7b7a4b921d9cfa3957408b43ae723,eb857bcd94857cedc4045cb2d6ba04cb5bbb3daf188abc95fb9478db823ef47e", + "-checkFileNameList=.gitignore,.gitattributes,push.yaml,release.yaml" ], - "env": [], - "stdin": null, - "stdout": null, - "stderr": null, - "cpuLimit": 0, + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, "realCpuLimit": 0, - "clockLimit": 0, - "memoryLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, "stackLimit": 0, - "procLimit": 0, + "procLimit": 50, "cpuRateLimit": 0, "cpuSetLimit": "", "copyIn": { - "tools/matlab-joj": { - "src": "tools/matlab-joj", + "/tmp/repo-health-checker": { + "src": "/tmp/repo-health-checker", "content": null, "fileId": null, "name": null, - "max": null, - "symlink": null, - "streamIn": false, - "streamOut": false, - "pipe": false - }, - "tools/matlab_formatter.py": { - "src": "tools/matlab_formatter.py", - "content": null, - "fileId": null, - "name": null, - "max": null, + "max": 4194304, "symlink": null, "streamIn": false, "streamOut": false, @@ -57,9 +83,139 @@ "copyInCached": {}, "copyInDir": ".", "copyOut": [], + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "healthcheck", + "with": { + "score": 0, + "comment": "" + } + } + ] + }, + { + "name": "Compilation", + "group": null, + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "make.sh" + ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": { + "tools/make.sh": { + "src": "/home/tt/.config/joj/tools/make.sh", + "content": null, + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "src/main.c": { + "src": "/home/tt/.config/joj/src/main.c", + "content": null, + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "src/task.h": { + "src": "/home/tt/.config/joj/src/task.h", + "content": null, + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "srcCMakelist.txt": { + "src": "/home/tt/.config/joj/srcCMakelist.txt", + "content": null, + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + } + }, + "copyInCached": { + "tools/make.sh": "tools/make.sh", + "src/main.c": "src/main.c", + "src/task.h": "src/task.h", + "srcCMakelist.txt": "srcCMakelist.txt" + }, + "copyInDir": ".", + "copyOut": [], "copyOutCached": [ - "output/ex5_results.txt", - "output/ex5_logs.txt" + "driver", + "p2", + "p2-msan" ], "copyOutMax": 0, "copyOutDir": "", @@ -73,7 +229,119 @@ }, "parsers": [ { - "name": "diff", + "name": "result-detail", + "with": { + "time": false, + "mem": false, + "stdout": false, + "stderr": true, + "exitstatus": true + } + }, + { + "name": "dummy", + "with": {} + }, + { + "name": "result-status", + "with": {} + } + ] + }, + { + "name": "File length check", + "group": null, + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "./file-length", + "500", + "400", + "*.c", + "*.h" + ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": { + "tools/file-length": { + "src": "/home/tt/.config/joj/tools/file-length", + "content": null, + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + } + }, + "copyInCached": { + "tools/file-length": "tools/file-length" + }, + "copyInDir": ".", + "copyOut": [], + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "keyword", + "with": {} + }, + { + "name": "dummy", "with": {} }, { @@ -82,65 +350,361 @@ "time": false, "mem": false, "stdout": false, - "stderr": true + "stderr": true, + "exitstatus": false } } ] }, { - "name": "judge_base2", - "group": "hw3 ex5", + "name": "Clang-tidy checks", + "group": null, "executor": { "name": "sandbox", "with": { "default": { "args": [ - "./matlab-joj", - "./h3/ex5.m" + "run-clang-tidy-18", + "-header-filter=.*", + "-quiet", + "-load=/usr/local/lib/libcodequality.so", + "-p", + "build" ], - "env": [], - "stdin": null, - "stdout": null, - "stderr": null, - "cpuLimit": 0, + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, "realCpuLimit": 0, - "clockLimit": 0, - "memoryLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, "stackLimit": 0, - "procLimit": 0, + "procLimit": 50, "cpuRateLimit": 0, "cpuSetLimit": "", - "copyIn": { - "tools/matlab-joj": { - "src": "tools/matlab-joj", - "content": null, - "fileId": null, - "name": null, - "max": null, - "symlink": null, - "streamIn": false, - "streamOut": false, - "pipe": false - }, - "tools/matlab_formatter.py": { - "src": "tools/matlab_formatter.py", - "content": null, - "fileId": null, - "name": null, - "max": null, - "symlink": null, - "streamIn": false, - "streamOut": false, - "pipe": false - } - }, + "copyIn": {}, "copyInCached": {}, "copyInDir": ".", "copyOut": [], - "copyOutCached": [ - "output/ex5_results2.txt", - "output/ex5_logs2.txt" + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "clangtidy", + "with": {} + }, + { + "name": "dummy", + "with": {} + }, + { + "name": "result-detail", + "with": { + "time": false, + "mem": false, + "stdout": true, + "stderr": false, + "exitstatus": true + } + } + ] + }, + { + "name": "Cppcheck check", + "group": null, + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "cppcheck", + "--template='{\"file\":\"{file}\",\"line\":{line},", + "\"column\":{column},", + "\"severity\":\"{severity}\",", + "\"message\":\"{message}\",", + "\"id\":\"{id}\"}'", + "--force", + "--enable=all", + "--quiet", + "./" ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": {}, + "copyInCached": {}, + "copyInDir": ".", + "copyOut": [], + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "cppcheck", + "with": {} + }, + { + "name": "dummy", + "with": {} + }, + { + "name": "result-detail", + "with": { + "time": false, + "mem": false, + "stdout": false, + "stderr": true, + "exitstatus": true + } + } + ] + }, + { + "name": "Cpplint check", + "group": null, + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "cpplint", + "--linelength=120", + "--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard", + "--recursive", + "--exclude=build", + "." + ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": {}, + "copyInCached": {}, + "copyInDir": ".", + "copyOut": [], + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "cpplint", + "with": {} + }, + { + "name": "dummy", + "with": {} + }, + { + "name": "result-detail", + "with": { + "time": false, + "mem": false, + "stdout": true, + "stderr": false, + "exitstatus": true + } + } + ] + }, + { + "name": "judge-base", + "group": "joj", + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "./driver", + "./mumsh" + ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": {}, + "copyInCached": {}, + "copyInDir": ".", + "copyOut": [], + "copyOutCached": [], "copyOutMax": 0, "copyOutDir": "", "tty": false, @@ -156,13 +720,109 @@ "name": "diff", "with": {} }, + { + "name": "dummy", + "with": {} + }, { "name": "result-detail", "with": { "time": true, "mem": true, "stdout": false, - "stderr": false + "stderr": true, + "exitstatus": true + } + } + ] + }, + { + "name": "judge-msan", + "group": "joj", + "executor": { + "name": "sandbox", + "with": { + "default": { + "args": [ + "./driver", + "./mumsh-msan" + ], + "env": [ + "PATH=/usr/bin:/bin:/usr/local/bin" + ], + "stdin": { + "src": null, + "content": "", + "fileId": null, + "name": null, + "max": 4194304, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stdout": { + "src": null, + "content": null, + "fileId": null, + "name": "stdout", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "stderr": { + "src": null, + "content": null, + "fileId": null, + "name": "stderr", + "max": 4096, + "symlink": null, + "streamIn": false, + "streamOut": false, + "pipe": false + }, + "cpuLimit": 4000000000, + "realCpuLimit": 0, + "clockLimit": 8000000000, + "memoryLimit": 4194304, + "stackLimit": 0, + "procLimit": 50, + "cpuRateLimit": 0, + "cpuSetLimit": "", + "copyIn": {}, + "copyInCached": {}, + "copyInDir": ".", + "copyOut": [], + "copyOutCached": [], + "copyOutMax": 0, + "copyOutDir": "", + "tty": false, + "strictMemoryLimit": false, + "dataSegmentLimit": false, + "addressSpaceLimit": false + }, + "cases": [] + } + }, + "parsers": [ + { + "name": "diff", + "with": {} + }, + { + "name": "dummy", + "with": {} + }, + { + "name": "result-detail", + "with": { + "time": true, + "mem": true, + "stdout": false, + "stderr": true, + "exitstatus": true } } ] @@ -170,10 +830,10 @@ ] }, "teapot": { - "logPath": "/home/tt/.cache/joint-teapot-debug.log", - "scoreboardPath": "scoreboard.csv", - "failedTablePath": "failed-table.md", - "gradingRepoName": "", + "logPath": "Homework-1-exercise-2-joint-teapot-debug.log", + "scoreboardPath": "Homework-1-exercise-2-scoreboard.csv", + "failedTablePath": "Homework-1-exercise-2-failed-table.md", + "gradingRepoName": "engr151-joj", "skipIssue": false, "skipScoreboard": false, "skipFailedTable": false diff --git a/tests/convert/basic/task.toml b/tests/convert/basic/task.toml index 0872079..ef299a4 100644 --- a/tests/convert/basic/task.toml +++ b/tests/convert/basic/task.toml @@ -1,30 +1,119 @@ -task = "hw3 ex5" +# general task configuration +task="Homework 1 exercise 2" # task name -[release] -deadline = "2024-10-18T23:59:00+08:00" +release.deadline = 2024-10-12 23:59:00+08:00 +release.stages = [ "compile" ] [[stages]] -name = "judge_base" -command = "./matlab-joj ./h3/ex5.m" -score = 100 -parsers = ["diff", "result-detail"] +name = "Compilation" +command = "make.sh" # eg. script running cmake commands +files.import = [ "tools/make.sh", "src/main.c", "src/task.h", "srcCMakelist.txt" ] +files.export = [ "driver", "p2", "p2-msan" ] +limit.cpu = 180 # p2 takes long to compile +limit.stderr = 128 -files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"] -files.export = ["output/ex5_results.txt", "output/ex5_logs.txt"] - -result_detail.time = false -result_detail.mem = false -result_detail.stderr = true +# compile parsers +parsers = [ "result-detail", "dummy", "result-status" ] +result-status.comment = "Congratulations! Your code compiled successfully." +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stderr = true +result-detail.time = false +result-detail.mem = false [[stages]] -name = "judge_base2" -command = "./matlab-joj ./h3/ex5.m" -score = 80 -parsers = ["diff", "result-detail"] +name = "File length check" +command = "./file-length 500 400 *.c *.h" # command to run +files.import = [ "tools/file-length" ] -files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"] -files.export = ["output/ex5_results2.txt", "output/ex5_logs2.txt"] +parsers = [ "keyword", "dummy", "result-detail" ] +keyword.keyword = [ "max", "recommend"] # keywords caught by corresponding JOJ plugin +keyword.weight = [ 50, 20 ] # weight of each keyword +result-detail.exitstatus = false +result-detail.stderr = true +result-detail.time = false +result-detail.mem = false -result_detail.time = true -result_detail.mem = true -result_detail.stderr = false +[[stages]] +name = "Clang-tidy checks" +command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p build" +limit.stdout = 65 + +parsers = [ "clangtidy", "dummy", "result-detail" ] +clangtidy.keyword = [ "codequality-no-global-variables", "codequality-no-header-guard", "readability-function-size", "readability-duplicate-include", "readability-identifier-naming", "readability-redundant", "readability-misleading-indentation", "readability-misplaced-array-index", "cppcoreguidelines-init-variables", "bugprone-suspicious-string-compare", "google-global-names-in-headers", "clang-diagnostic", "clang-analyzer", "misc performance" ] +clangtidy.weight = [10, 10, 50, 10, 5, 5, 10, 5, 5, 8, 5, 5, 5, 5, 8] +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stdout = true +result-detail.time = false +result-detail.mem = false + +[[stages]] +name = "Cppcheck check" +command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --quiet ./" +limit.stderr = 65 + +parsers = [ "cppcheck", "dummy", "result-detail" ] +cppcheck.keyword = ["error", "warning", "portability", "performance", "style"] +cppcheck.weight = [20, 10, 15, 15, 10] +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stderr = true +result-detail.time = false +result-detail.mem = false + +[[stages]] +name = "Cpplint check" +command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard --recursive --exclude=build ." +limit.stdout = 65 + +parsers = [ "cpplint", "dummy", "result-detail" ] +cpplint.keyword = [ "runtime", "readability", "build" ] +cpplint.weight = [ 10, 20, 15] +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stdout = true +result-detail.time = false +result-detail.mem = false + +[[stages]] +name = "judge-base" +command="./driver ./mumsh" +limit.cpu = 3 +limit.mem = 75 +score = 10 + +parsers = ["diff", "dummy", "result-detail"] +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stderr = true + +case4.score = 15 +case4.limit.cpu = 30 +case4.limit.mem = 10 +case4.limit.stdout = 8 + +case5.score = 25 + +case8.limit.stderr = 128 + +[[stages]] +name = "judge-msan" +command="./driver ./mumsh-msan" +limit.cpu = 10 # default cpu limit (in sec) for each test case +limit.mem = 500 # set default mem limit (in MB) for all OJ test cases +score = 10 +skip = ["case0", "case11"] + +parsers = ["diff", "dummy", "result-detail"] +dummy.comment = "\n\n### Details\n" +result-detail.exitstatus = true +result-detail.stderr = true + +case4.score = 15 +case4.limit.cpu = 30 +case4.limit.mem = 10 + +case5.diff.output.ignorespaces = false + +case6.diff.output.hide = true diff --git a/tests/immutable_file/.gitattributes b/tests/immutable_file/.gitattributes new file mode 100644 index 0000000..b910c4a --- /dev/null +++ b/tests/immutable_file/.gitattributes @@ -0,0 +1,33 @@ +*.avi filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.djvu filter=lfs diff=lfs merge=lfs -text +*.doc filter=lfs diff=lfs merge=lfs -text +*.docx filter=lfs diff=lfs merge=lfs -text +*.epub filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.ipynb filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.JPEG filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.JPG filter=lfs diff=lfs merge=lfs -text +*.mkv filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.ods filter=lfs diff=lfs merge=lfs -text +*.odt filter=lfs diff=lfs merge=lfs -text +*.otf filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.PDF filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.PNG filter=lfs diff=lfs merge=lfs -text +*.ppt filter=lfs diff=lfs merge=lfs -text +*.pptx filter=lfs diff=lfs merge=lfs -text +*.ps filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.webm filter=lfs diff=lfs merge=lfs -text +*.xls filter=lfs diff=lfs merge=lfs -text +*.xlsx filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text diff --git a/tests/immutable_file/.gitignore b/tests/immutable_file/.gitignore new file mode 100644 index 0000000..754f776 --- /dev/null +++ b/tests/immutable_file/.gitignore @@ -0,0 +1,23 @@ +################################ +## White list based gitignore ## +################################ + +# forbidden +* +.* + +# allowed +!.gitignore +!.gitattributes +!.gitea/ +!.gitea/issue_template/ +!.gitea/workflows/ +!*.yaml +!Makefile +!CMakeLists.txt +!h[0-8]/ +!*.m +!*.c +!*.cpp +!*.h +!*.md diff --git a/tests/immutable_file/push.yaml b/tests/immutable_file/push.yaml new file mode 100644 index 0000000..2f890b6 --- /dev/null +++ b/tests/immutable_file/push.yaml @@ -0,0 +1,18 @@ +name: Run JOJ3 on Push +on: [push] +jobs: + run: + container: + image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim + volumes: + - /home/tt/.config:/home/tt/.config + - /home/tt/.cache:/home/tt/.cache + - /home/tt/.ssh:/home/tt/.ssh + steps: + - name: Check out repository code + uses: https://gitea.com/BoYanZh/checkout@focs + with: + fetch-depth: 0 + - name: run joj3 + run: | + sudo -E -u tt joj3 -conf-root /home/tt/.config/joj diff --git a/tests/immutable_file/release.yaml b/tests/immutable_file/release.yaml new file mode 100644 index 0000000..afd2838 --- /dev/null +++ b/tests/immutable_file/release.yaml @@ -0,0 +1,20 @@ +name: Run JOJ3 on Release +on: + release: + types: [published] +jobs: + run: + container: + image: focs.ji.sjtu.edu.cn:5000/gitea/runner-images:focs-ubuntu-latest-slim + volumes: + - /home/tt/.config:/home/tt/.config + - /home/tt/.cache:/home/tt/.cache + - /home/tt/.ssh:/home/tt/.ssh + steps: + - name: Check out repository code + uses: https://gitea.com/BoYanZh/checkout@focs + with: + fetch-depth: 0 + - name: run joj3 + run: | + sudo -E -u tt joj3 -conf-root /home/tt/.config/joj -msg "feat(h1-release): joj on ${{ github.ref }}"