name: judge run-name: "Sum tests (${{ inputs.student_url || github.repository }})" on: push: pull_request: workflow_dispatch: inputs: student_url: description: "Student repo (owner/repo), leave empty to use current repo" required: false type: string default: "" student_ref: description: "Ref (branch / tag / SHA)" required: false type: string default: "main" env: SUITE_FILE: sum.jdg SOURCES_DIR: __sources__ EXAMPLE_DIR: example/c-sum jobs: # Build judge once for all platforms, then ship the binaries as an artifact. # test jobs just download and run them — no Go needed on test runners. build_judge: name: Build judge runs-on: Linux-Runner timeout-minutes: 10 steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Cross-compile judge shell: bash run: | mkdir -p dist CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/judge-linux-amd64 ./cmd/cli CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o dist/judge-windows-amd64.exe ./cmd/cli ls -la dist/ - name: Upload judge binaries uses: https://github.com/christopherHX/gitea-upload-artifact@v4 with: name: judge-bin path: dist/ retention-days: 1 test: needs: build_judge name: "${{ matrix.toolchain.system }} / ${{ matrix.toolchain.use_compiler }} / ${{ matrix.toolchain.build_type }}${{ matrix.toolchain.wrapper != 'no' && format(' ({0})', matrix.toolchain.wrapper) || '' }}" strategy: fail-fast: false matrix: toolchain: - { system: Linux, use_compiler: gcc, build_type: Release, cflags: "-O2", wrapper: no } - { system: Linux, use_compiler: gcc, build_type: Debug, cflags: "-O0 -g", wrapper: no } - { system: Linux, use_compiler: gcc, build_type: Sanitized, cflags: "-O1 -g -fsanitize=address,undefined", wrapper: no } - { system: Linux, use_compiler: gcc, build_type: Debug, cflags: "-O0 -g", wrapper: valgrind } - { system: Linux, use_compiler: clang, build_type: Release, cflags: "-O2", wrapper: no } - { system: Linux, use_compiler: clang, build_type: Sanitized, cflags: "-O1 -g -fsanitize=address,undefined", wrapper: no } - { system: Windows, use_compiler: clang, build_type: Release, cflags: "-O2", wrapper: no } - { system: Windows, use_compiler: clang, build_type: Debug, cflags: "-O0 -g", wrapper: no } - { system: Windows, use_compiler: msvc, build_type: Release, cflags: "/O2", wrapper: no } - { system: Windows, use_compiler: msvc, build_type: Debug, cflags: "/Od /Zi", wrapper: no } runs-on: ${{ matrix.toolchain.system }}-Runner timeout-minutes: 10 env: REPORT_NAME: "report_${{ matrix.toolchain.system }}_${{ matrix.toolchain.use_compiler }}_${{ matrix.toolchain.build_type }}_${{ matrix.toolchain.wrapper }}" CC: ${{ matrix.toolchain.use_compiler }} CFLAGS: ${{ matrix.toolchain.cflags }} steps: - name: Checkout judge harness uses: actions/checkout@v4 - name: Checkout student sources if: ${{ inputs.student_url != '' }} uses: actions/checkout@v4 with: repository: ${{ inputs.student_url }} ref: ${{ inputs.student_ref }} path: ${{ env.SOURCES_DIR }} token: ${{ secrets.VAR_TOKEN }} - name: Stage sources (self) if: ${{ inputs.student_url == '' }} shell: bash run: | mkdir -p "${SOURCES_DIR}" cp "${EXAMPLE_DIR}/solution.c" "${SOURCES_DIR}/" - name: Set up MSVC environment if: matrix.toolchain.use_compiler == 'msvc' uses: ilammy/msvc-dev-cmd@v1 - name: Download judge binary uses: https://github.com/christopherHX/gitea-download-artifact@v4 with: name: judge-bin path: judge-bin - name: Install judge on PATH shell: bash run: | mkdir -p bin if [ "${{ matrix.toolchain.system }}" = "Windows" ]; then cp judge-bin/judge-windows-amd64.exe bin/judge.exe else cp judge-bin/judge-linux-amd64 bin/judge chmod +x bin/judge fi echo "$PWD/bin" >> "$GITHUB_PATH" - name: Install valgrind if: matrix.toolchain.wrapper == 'valgrind' run: sudo apt-get update && sudo apt-get install -y valgrind - name: Run judge shell: bash working-directory: ${{ env.SOURCES_DIR }} env: WRAPPER: ${{ matrix.toolchain.wrapper }} run: | cp "../${EXAMPLE_DIR}/${SUITE_FILE}" . WRAPPER_ARG="" case "$WRAPPER" in valgrind) WRAPPER_ARG='--wrapper=valgrind --error-exitcode=99 --leak-check=full -q' ;; no) WRAPPER_ARG="" ;; *) WRAPPER_ARG="--wrapper=$WRAPPER" ;; esac # runner auto-detects .exe suffix on Windows judge "$SUITE_FILE" . --json $WRAPPER_ARG > "$GITHUB_WORKSPACE/${REPORT_NAME}.json" \ || echo "judge exited non-zero (expected when tests fail)" judge "$SUITE_FILE" . $WRAPPER_ARG || true - name: Upload report if: ${{ always() }} uses: https://github.com/christopherHX/gitea-upload-artifact@v4 with: name: ${{ env.REPORT_NAME }} path: ${{ env.REPORT_NAME }}.json retention-days: 7 compression-level: 9 summary: needs: [test] if: ${{ always() }} name: SUMMARY runs-on: Linux-Runner timeout-minutes: 5 steps: - name: Download all reports uses: https://github.com/christopherHX/gitea-download-artifact@v4 with: path: reports pattern: report_* - name: Aggregate shell: bash run: | echo "# Judge results" > SUMMARY.md echo "" >> SUMMARY.md echo "| Configuration | Score |" >> SUMMARY.md echo "|---|---|" >> SUMMARY.md for f in reports/*/*.json; do cfg=$(basename "$(dirname "$f")" | sed 's/^report_//') score=$(grep -o '"TotalScore":[^,}]*' "$f" | head -1 | cut -d: -f2) echo "| $cfg | $score |" >> SUMMARY.md done cat SUMMARY.md - name: Upload summary uses: https://github.com/christopherHX/gitea-upload-artifact@v4 with: name: SUMMARY path: SUMMARY.md retention-days: 7