关于如何利用github搭建一个自己的OJ
前言
最近,有机会接触到了利用github的classroom简单设计一个小的操作系统竞赛的OJ,并可以生成排行榜的项目。当然,这其中用到了很多开源项目。
实质就技术而言并不复杂,但是无奈于github classroom的文档太缺了,配备的autograding机制和成绩收集机制有点太简单了,无法支撑复杂功能,并在踩坑的路上花了很多时间。当然,如果你不是基于classroom存储成绩可能反而会没这么麻烦。你只需要有一个组织,建一个classroom,在classroom里利用模板仓库(主要是编写workflow)生成一个assignment,然后基于一个开源项目获取classroom的数据并生成网页。
你需要organization,classroom,assignment,模板仓库(template CI),测例脚本(各种语言编写的),部署网站仓库。
基本流程
现在简单讲一下流程。
-
首先,你需要建立一个组织,或者加入一个组织成为这个组织的owner。
-
然后,你就可以建立该组织下的classroom了。
-
之后,你就可以建立一个assignment了,然后你就可以邀请其他人加入教室,接受任务了,classroom会自动为其他人生成仓库。
这几步都很简单自然,最重要的就是github模板仓库的编写。
模板仓库最大的作用就是编写CI流,也即是.github/workflows中文件的内容。如果之前没接触过github的CI,可以先去看看基本用法,很好上手。它就是在你的各种设置触发要求下,github服务器会自行运行你编写的CI。具体编写方法就不细讲了,可以自行去看。
然后详细讲一下关于autograding的部分。它实际分为两部分autograding-test和autograding-reporter。前者负责测试吗,后者负责把测试结果报告给classroom。
现在classroom它自己提供了很简单的写法和一些仓库包括python和js之类的,大家在搭建assignment时就可以看到。
比如:
你可以根据add_test的选项和你自己测例脚本的配置来自行选择,它会自动帮你生成相应的CI。优点是简单,缺点是无法支撑复杂配置。
如果你的测试脚本是js,那么你可以对其进行一些魔改,或者改用24年之前的仓库版本。
注意事项
在这里无论你是用自动生成的还是自己编写的脚本,你都需要注意以下几点:
- CI名必须为Autograding Tests
- 整个CI只能有一个job
- check点的名字必须为run-autograding-tests
- 测试名必须为testname-test的形式(存疑)
- autograding-grading-reporter的环境变量输入必须为之前test的id大写字母_RESULTS
- 最多只支持16个test
下面给出一个示例:
name: Autograding Tests
on:
push:
branches:
- main
# paths-ignore:
# - '.github/**'
env:
IMG_URL_riscv64: https://github.com/Azure-stars/testsuits-for-oskernel/releases/download/v0.1/sdcard-riscv64.img.gz # 镜像url
IMG_URL_x86_64: https://github.com/Azure-stars/testsuits-for-oskernel/releases/download/v0.1/sdcard-x86_64.img.gz # 镜像url
TIMEOUT: 300 # 超时时间
SCRIPT_REPO: https://github.com/oscontent25/EvaluationScript # 脚本仓库
jobs:
run-autograding-tests:
runs-on: ubuntu-latest
env:
qemu-version: 9.2.1
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: nightly-2025-01-18
components: rust-src, llvm-tools
targets: x86_64-unknown-none, riscv64gc-unknown-none-elf, aarch64-unknown-none, aarch64-unknown-none-softfloat, loongarch64-unknown-none
- uses: Swatinem/rust-cache@v2
- run: cargo install cargo-binutils
- uses: ./.github/workflows/setup-musl
with:
arch: riscv64
- uses: ./.github/workflows/setup-musl
with:
arch: x86_64
- uses: ./.github/workflows/setup-qemu
with:
qemu-version: $
- name: Build python environment
run: sudo apt-get install -y python3 python3-pip
- name: build os.bin
run: |
touch riscv64_output.txt
touch x86_64_output.txt
make oscomp_run ARCH=riscv64 BLK=y NET=y FEATURES=fp_simd,lwext4_rs > riscv64_output.txt || true
make clean
make oscomp_run ARCH=x86_64 BLK=y NET=y FEATURES=fp_simd,lwext4_rs ACCEL=n > x86_64_output.txt || true
- name: Download EvaluationScript
run: |
git clone $ .github/classroom
- name: riscvglibc-test
uses: oscontent25/os-autograding@master
id: autogradingriscvglibc
with:
outputfile: riscv64_output.txt
scriptPath: .github/classroom/glibc
- name: x86musl-test
uses: oscontent25/os-autograding@master
id: autogradingx86musl
with:
outputfile: x86_64_output.txt
scriptPath: .github/classroom/musl
- name: Autograding Reporter
uses: classroom-resources/autograding-grading-reporter@v1
env:
AUTOGRADINGRISCVGLIBC_RESULTS: "$"
AUTOGRADINGX86MUSL_RESULTS: "$"
with:
runners: autogradingriscvglibc,autogradingx86musl
token: $
你可以看见这个CI的基本流程,主要是环境搭建、测试和收集成绩报告给classroom,有一些小错误,完整版你可以看最后的仓库。 这里用到的os-autograding是经过魔改后的,我最后用的autograding-grading-reporter也是自己魔改的,当然在这里展示的不是。你可以通过访问魔改仓库,因为这实际上是老仓库fork过来的,为了和新的autograding相适配我不得不进行一些魔改。理所当然,为了丰富功能,我对新的autograding-reporter也进行了适配。
这里给出测试脚本仓库
比较关键的逻辑是每个测试脚本都会返回一个points的数据,具体你可以参考脚本内容。
当然这里处理的都是针对于你运行一个东西,得到输出,再将输出输入autograing进行评判。这种逻辑很简单,可以你可以自行加入一些反作弊机制。
这里给出一个完整的CI,这也是上文所说的类似操作系统竞赛的OJ。你可以通过这个template来搭建自己的OJ。
结语
关于网站部署,你可以参考原版,也可以参考魔改之后的仓库,魔改之后相较前面多了各测例得分,你可以自己阅读代码,查看逻辑。本身是由于classroom在同一个assignment下只记录总分,不记录各类测例得分,不然只能用多个模板仓库建立多个assignment,这样很不方便。所以我就魔改os-autograding和autograding-grading-reporter采取特殊的编码方式把各类测例得分编码进总分,再在部署网页的仓库进行相应的解码。
希望能对你有用!
版权声明: 如无特别声明,本文版权归 Mr Huang 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:《 github classroom 》
本文链接:https://wingrew.com/exercise/github_classroom.html
本文最后一次更新为 天前,文章中的某些内容可能已过时!