Compare commits
5 Commits
61c9dcebb7
...
c474a5d493
Author | SHA1 | Date | |
---|---|---|---|
c474a5d493 | |||
19bcc90ae9 | |||
a834e0ff17 | |||
7254c48f9a | |||
49b7c7c5db |
72
README.md
72
README.md
|
@ -96,78 +96,6 @@ These steps are executed in runner-images. We use `sudo -u tt` to elevate the pe
|
||||||
5. Generate results.
|
5. Generate results.
|
||||||
- Once the running of stages is done, it will generate a result file where the path is specified in the configuration file.
|
- Once the running of stages is done, it will generate a result file where the path is specified in the configuration file.
|
||||||
|
|
||||||
## Components
|
|
||||||
|
|
||||||
### Binaries (under `/cmd` and `/pkg`)
|
|
||||||
|
|
||||||
#### JOJ3
|
|
||||||
|
|
||||||
JOJ3 itself. Parsers and executors are compiled into the JOJ3 binary.
|
|
||||||
|
|
||||||
#### Sample
|
|
||||||
|
|
||||||
Just a sample on how to write an executable that can be called by the executor.
|
|
||||||
|
|
||||||
#### HealthCheck
|
|
||||||
|
|
||||||
The repohealth check will return a json list to for check result. The structure follows the score-comment pattern.
|
|
||||||
|
|
||||||
HealthCheck currently includes, `reposize`, `forbidden file`, `Metafile existence`, `non-ascii character` in file and message, `release tag`, and `ci files invariance` check.
|
|
||||||
|
|
||||||
The workflow is `joj3` pass cli args to healthcheck binary. See `./cmd/healthcheck/main.go` to view all flags.
|
|
||||||
|
|
||||||
### Executors (under `/internal/executors`)
|
|
||||||
|
|
||||||
#### Dummy
|
|
||||||
|
|
||||||
Do not execute any command. Just return empty `ExecutorResult` slice.
|
|
||||||
|
|
||||||
#### Sandbox
|
|
||||||
|
|
||||||
Run the commands in `go-judge` and output the `ExecutorResult` slice. Note: we communicate with `go-judge` using gRPC, which means `go-judge` can run anywhere as the gRPC connection can be established. In deployment, `go-judge` runs in the host machine of the Gitea runner.
|
|
||||||
|
|
||||||
### Parsers (under `/internal/parsers`)
|
|
||||||
|
|
||||||
#### Clang Tidy
|
|
||||||
|
|
||||||
Parser for `clang-tidy`, check `/examples/clangtidy` on how to call `clang-tidy` with proper parameters.
|
|
||||||
|
|
||||||
#### Cppcheck
|
|
||||||
|
|
||||||
Parser for `cppcheck`, check `/examples/cppcheck` on how to call `cppcheck` with proper parameters.
|
|
||||||
|
|
||||||
#### Cpplint
|
|
||||||
|
|
||||||
Parser for `cpplint`, check `/examples/cpplint` on how to call `cpplint` with proper parameters.
|
|
||||||
|
|
||||||
#### Diff
|
|
||||||
|
|
||||||
Compare the specified output of `ExecutorResult` with the content of the answer file. If they are the same, then score will be given. Just like a normal online judge system.
|
|
||||||
|
|
||||||
#### Dummy
|
|
||||||
|
|
||||||
Does not parse the output of `ExecutorResult`. It just output what is set inside the configuration file as score and comment. Currently it is used to output metadata for `joint-teapot`.
|
|
||||||
|
|
||||||
In `joint-teapot`, it will take the content before `-` of the comment of the first stage with name `metadata` as the exercise name and record in the scoreboard. (e.g. If the comment is `p2-s2-0xdeadbeef`, then the exercise name is `p2`.)
|
|
||||||
|
|
||||||
The comment in `metadata` can also be used to skip teapot commands. With `skip-teapot` in the comment, teapot will not run. And with `skip-scoreboard`, `skip-failed-table`, and `skip-result-issue`, only the corresponding step will be skipped, while the others will be executed. (e.g. If the comment is `p2-s2-0xdeadbeef-skip-scoreboard-skip-result-issue`, then only failed table step in teapot will run.)
|
|
||||||
|
|
||||||
#### Healthcheck
|
|
||||||
|
|
||||||
Parser for the `healthcheck` binary mentioned before.
|
|
||||||
|
|
||||||
#### Keyword
|
|
||||||
|
|
||||||
Match the given keyword from the specified output of `ExecutorResult`. For each match, a deduction of score is given. Can be useful if we do not have a specific parser for a code quality tool. Check `/examples/keyword`.
|
|
||||||
|
|
||||||
#### Result Status
|
|
||||||
|
|
||||||
Only check if all the status of the executor is `StatusAccepted`. Can be used to check whether the command run in the executor exit normally.
|
|
||||||
|
|
||||||
#### Sample
|
|
||||||
|
|
||||||
Parser for the `sample` binary mentioned before. Only used as a sample.
|
|
||||||
|
|
||||||
## Models (for developers only)
|
## Models (for developers only)
|
||||||
|
|
||||||
The program parses the configuration file to run multiple stages.
|
The program parses the configuration file to run multiple stages.
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/conf"
|
||||||
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
||||||
"github.com/joint-online-judge/JOJ3/internal/conf"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var runningTest bool
|
var runningTest bool
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Package main provides a joj3 executable, which runs various stages based on
|
||||||
|
// configuration files and commit message. The output is a JSON file.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -7,9 +9,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
joj3Conf "github.com/joint-online-judge/JOJ3/cmd/joj3/conf"
|
||||||
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
||||||
"github.com/joint-online-judge/JOJ3/cmd/joj3/stage"
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/stage"
|
||||||
internalConf "github.com/joint-online-judge/JOJ3/internal/conf"
|
|
||||||
internalStage "github.com/joint-online-judge/JOJ3/internal/stage"
|
internalStage "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +33,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mainImpl() (err error) {
|
func mainImpl() (err error) {
|
||||||
conf := new(internalConf.Conf)
|
conf := new(joj3Conf.Conf)
|
||||||
|
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
slog.SetDefault(logger)
|
slog.SetDefault(logger)
|
||||||
|
@ -46,13 +48,13 @@ func mainImpl() (err error) {
|
||||||
fallbackConfFileName = confFileName
|
fallbackConfFileName = confFileName
|
||||||
}
|
}
|
||||||
slog.Info("start joj3", "version", Version)
|
slog.Info("start joj3", "version", Version)
|
||||||
commitMsg, err := internalConf.GetCommitMsg()
|
commitMsg, err := joj3Conf.GetCommitMsg()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("get commit msg", "error", err)
|
slog.Error("get commit msg", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
env.Attr.CommitMsg = commitMsg
|
env.Attr.CommitMsg = commitMsg
|
||||||
confPath, confStat, conventionalCommit, err := internalConf.GetConfPath(
|
confPath, confStat, conventionalCommit, err := joj3Conf.GetConfPath(
|
||||||
confFileRoot, confFileName, fallbackConfFileName, commitMsg, tag,
|
confFileRoot, confFileName, fallbackConfFileName, commitMsg, tag,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -60,7 +62,7 @@ func mainImpl() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
slog.Info("try to load conf", "path", confPath)
|
slog.Info("try to load conf", "path", confPath)
|
||||||
conf, err = internalConf.ParseConfFile(confPath)
|
conf, err = joj3Conf.ParseConfFile(confPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("parse conf", "error", err)
|
slog.Error("parse conf", "error", err)
|
||||||
return err
|
return err
|
||||||
|
@ -74,20 +76,20 @@ func mainImpl() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// log conf file info
|
// log conf file info
|
||||||
confSHA256, err := internalConf.GetSHA256(confPath)
|
confSHA256, err := joj3Conf.GetSHA256(confPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("get sha256", "error", err)
|
slog.Error("get sha256", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
slog.Info("conf info", "sha256", confSHA256, "modTime", confStat.ModTime(),
|
slog.Info("conf info", "sha256", confSHA256, "modTime", confStat.ModTime(),
|
||||||
"size", confStat.Size())
|
"size", confStat.Size())
|
||||||
if err := internalConf.CheckExpire(conf); err != nil {
|
if err := joj3Conf.CheckExpire(conf); err != nil {
|
||||||
slog.Error("conf check expire", "error", err)
|
slog.Error("conf check expire", "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// run stages
|
// run stages
|
||||||
groups := internalConf.MatchGroups(conf, conventionalCommit)
|
groups := joj3Conf.MatchGroups(conf, conventionalCommit)
|
||||||
env.Attr.Groups = strings.Join(groups, ",")
|
env.Attr.Groups = strings.Join(groups, ",")
|
||||||
env.Set()
|
env.Set()
|
||||||
_, forceQuitStageName, err := stage.Run(
|
_, forceQuitStageName, err := stage.Run(
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/joint-online-judge/JOJ3/internal/conf"
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/conf"
|
||||||
executors "github.com/joint-online-judge/JOJ3/internal/executor"
|
executors "github.com/joint-online-judge/JOJ3/internal/executor"
|
||||||
_ "github.com/joint-online-judge/JOJ3/internal/parser"
|
_ "github.com/joint-online-judge/JOJ3/internal/parser"
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package main provides a repo-health-checker executable that checks the
|
||||||
|
// health of a repository. Its output should be parsed by the healthcheck
|
||||||
|
// parser.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Package main provides a sample executable that demonstrates how JOJ3 works.
|
||||||
|
// Its output should be parsed by the sample parser.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Dummy struct{}
|
|
||||||
|
|
||||||
func (e *Dummy) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Dummy) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
var res []stage.ExecutorResult
|
var res []stage.ExecutorResult
|
||||||
for range cmds {
|
for range cmds {
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
// Package dummy provides a mock executor implementation for testing purposes
|
||||||
|
// and serves as a template for new executor development. It always returns
|
||||||
|
// a empty accepted result.
|
||||||
package dummy
|
package dummy
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "dummy"
|
var name = "dummy"
|
||||||
|
|
||||||
|
type Dummy struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterExecutor(name, &Dummy{})
|
stage.RegisterExecutor(name, &Dummy{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Local struct{}
|
|
||||||
|
|
||||||
func generateResult(
|
func generateResult(
|
||||||
err error,
|
err error,
|
||||||
processState *os.ProcessState,
|
processState *os.ProcessState,
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
// Package local implements an executor that runs commands directly on the local
|
||||||
|
// system. It passes current environment variables to the command, which can be
|
||||||
|
// used for passing run time parameters.
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "local"
|
var name = "local"
|
||||||
|
|
||||||
|
type Local struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterExecutor(name, &Local{})
|
stage.RegisterExecutor(name, &Local{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,6 @@ import (
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Sandbox struct {
|
|
||||||
execServer, token string
|
|
||||||
cachedMap map[string]string
|
|
||||||
execClient pb.ExecutorClient
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Sandbox) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Sandbox) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
var err error
|
var err error
|
||||||
if e.execClient == nil {
|
if e.execClient == nil {
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
|
// Package sandbox provides a sandboxed execution environment for running
|
||||||
|
// untrusted code. It integrates with the go-judge execution service to provide
|
||||||
|
// isolated and secure code execution. By default, it uses gRPC to communicate
|
||||||
|
// with go-judge.
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/criyle/go-judge/pb"
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
var name = "sandbox"
|
var name = "sandbox"
|
||||||
|
|
||||||
|
type Sandbox struct {
|
||||||
|
execServer, token string
|
||||||
|
cachedMap map[string]string
|
||||||
|
execClient pb.ExecutorClient
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterExecutor(name, &Sandbox{
|
stage.RegisterExecutor(name, &Sandbox{
|
||||||
execServer: "localhost:5051",
|
execServer: "localhost:5051",
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
|
// Package clangtidy parses output of the clang-tidy C/C++ linter tool to assign
|
||||||
|
// scores based on detected code issues.
|
||||||
package clangtidy
|
package clangtidy
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "clangtidy"
|
var name = "clangtidy"
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Keywords []string
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
RootDir string `default:"/w"`
|
||||||
|
Matches []Match
|
||||||
|
Stdout string `default:"stdout"`
|
||||||
|
Stderr string `default:"stderr"`
|
||||||
|
ForceQuitOnDeduct bool `default:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClangTidy struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &ClangTidy{})
|
stage.RegisterParser(name, &ClangTidy{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
|
||||||
Keywords []string
|
|
||||||
Score int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
RootDir string `default:"/w"`
|
|
||||||
Matches []Match
|
|
||||||
Stdout string `default:"stdout"`
|
|
||||||
Stderr string `default:"stderr"`
|
|
||||||
ForceQuitOnDeduct bool `default:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClangTidy struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
stdout := executorResult.Files[conf.Stdout]
|
stdout := executorResult.Files[conf.Stdout]
|
||||||
// stderr := executorResult.Files[conf.Stderr]
|
// stderr := executorResult.Files[conf.Stderr]
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
|
// Package clangtidy parses output of the cppcheck static analysis tool to
|
||||||
|
// assign scores based on detected code issues.
|
||||||
|
// Check examples on running cppcheck for parseable output.
|
||||||
package cppcheck
|
package cppcheck
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "cppcheck"
|
var name = "cppcheck"
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Keywords []string
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Matches []Match
|
||||||
|
Stdout string `default:"stdout"`
|
||||||
|
Stderr string `default:"stderr"`
|
||||||
|
ForceQuitOnDeduct bool `default:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CppCheck struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &CppCheck{})
|
stage.RegisterParser(name, &CppCheck{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
|
||||||
Keywords []string
|
|
||||||
Score int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Matches []Match
|
|
||||||
Stdout string `default:"stdout"`
|
|
||||||
Stderr string `default:"stderr"`
|
|
||||||
ForceQuitOnDeduct bool `default:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Record struct {
|
type Record struct {
|
||||||
File string `json:"file"`
|
File string `json:"file"`
|
||||||
Line int `json:"line"`
|
Line int `json:"line"`
|
||||||
|
@ -30,8 +17,6 @@ type Record struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CppCheck struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
// stdout := executorResult.Files[conf.Stdout]
|
// stdout := executorResult.Files[conf.Stdout]
|
||||||
stderr := executorResult.Files[conf.Stderr]
|
stderr := executorResult.Files[conf.Stderr]
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
|
// Package clangtidy parses output of the cpplint style checker tool to assign
|
||||||
|
// scores based on detected code issues.
|
||||||
package cpplint
|
package cpplint
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "cpplint"
|
var name = "cpplint"
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Keywords []string
|
||||||
|
Score int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Matches []Match
|
||||||
|
Stdout string `default:"stdout"`
|
||||||
|
Stderr string `default:"stderr"`
|
||||||
|
ForceQuitOnDeduct bool `default:"false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cpplint struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Cpplint{})
|
stage.RegisterParser(name, &Cpplint{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,21 +9,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
|
||||||
Keywords []string
|
|
||||||
Score int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Matches []Match
|
|
||||||
Stdout string `default:"stdout"`
|
|
||||||
Stderr string `default:"stderr"`
|
|
||||||
ForceQuitOnDeduct bool `default:"false"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Cpplint struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
stderr := executorResult.Files[conf.Stderr]
|
stderr := executorResult.Files[conf.Stderr]
|
||||||
pattern := `(.+):(\d+): (.+) \[(.+)\] \[(\d)]\n`
|
pattern := `(.+):(\d+): (.+) \[(.+)\] \[(\d)]\n`
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
// Package debug logs the executor result to help in troubleshooting.
|
||||||
package debug
|
package debug
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "debug"
|
var name = "debug"
|
||||||
|
|
||||||
|
type Conf struct{}
|
||||||
|
|
||||||
|
type Debug struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Debug{})
|
stage.RegisterParser(name, &Debug{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct{}
|
|
||||||
|
|
||||||
type Debug struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
slog.Debug("debug parser", "executorResult", executorResult)
|
slog.Debug("debug parser", "executorResult", executorResult)
|
||||||
for name, content := range executorResult.Files {
|
for name, content := range executorResult.Files {
|
||||||
|
|
|
@ -1,9 +1,32 @@
|
||||||
|
// Package diff implements string comparison functionality for the specific
|
||||||
|
// output files, comparing then with expected answers and assigning scores based
|
||||||
|
// on results.
|
||||||
package diff
|
package diff
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "diff"
|
var name = "diff"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
PassComment string `default:"🥳Passed!\n"`
|
||||||
|
FailComment string `default:"🧐Failed...\n"`
|
||||||
|
FailOnNotAccepted bool `default:"true"`
|
||||||
|
ForceQuitOnFailed bool `default:"false"`
|
||||||
|
Cases []struct {
|
||||||
|
Outputs []struct {
|
||||||
|
Score int
|
||||||
|
FileName string
|
||||||
|
AnswerPath string
|
||||||
|
CompareSpace bool
|
||||||
|
AlwaysHide bool
|
||||||
|
ForceQuitOnDiff bool
|
||||||
|
MaxDiffLength int `default:"2048"` // just for reference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Diff struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Diff{})
|
stage.RegisterParser(name, &Diff{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,26 +19,6 @@ const (
|
||||||
MOVE
|
MOVE
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
PassComment string `default:"🥳Passed!\n"`
|
|
||||||
FailComment string `default:"🧐Failed...\n"`
|
|
||||||
FailOnNotAccepted bool `default:"true"`
|
|
||||||
ForceQuitOnFailed bool `default:"false"`
|
|
||||||
Cases []struct {
|
|
||||||
Outputs []struct {
|
|
||||||
Score int
|
|
||||||
FileName string
|
|
||||||
AnswerPath string
|
|
||||||
CompareSpace bool
|
|
||||||
AlwaysHide bool
|
|
||||||
ForceQuitOnDiff bool
|
|
||||||
MaxDiffLength int `default:"2048"` // just for reference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Diff struct{}
|
|
||||||
|
|
||||||
func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
|
func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
[]stage.ParserResult, bool, error,
|
[]stage.ParserResult, bool, error,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
|
// Package dummy provides a simple parser implementation that serves as a
|
||||||
|
// template for new parser development.
|
||||||
package dummy
|
package dummy
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "dummy"
|
var name = "dummy"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Comment string
|
||||||
|
ForceQuit bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dummy struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Dummy{})
|
stage.RegisterParser(name, &Dummy{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Comment string
|
|
||||||
ForceQuit bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Dummy struct{}
|
|
||||||
|
|
||||||
func (*Dummy) Run(results []stage.ExecutorResult, confAny any) (
|
func (*Dummy) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
[]stage.ParserResult, bool, error,
|
[]stage.ParserResult, bool, error,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
|
// Package healthcheck parses the output of the repo-health-checker tool and
|
||||||
|
// return forced quit status on error.
|
||||||
package healthcheck
|
package healthcheck
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "healthcheck"
|
var name = "healthcheck"
|
||||||
|
|
||||||
|
type Healthcheck struct{}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Stdout string `default:"stdout"`
|
||||||
|
Stderr string `default:"stderr"`
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Healthcheck{})
|
stage.RegisterParser(name, &Healthcheck{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/pkg/healthcheck"
|
"github.com/joint-online-judge/JOJ3/pkg/healthcheck"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Healthcheck struct{}
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Stdout string `default:"stdout"`
|
|
||||||
Stderr string `default:"stderr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) (stage.ParserResult, bool) {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) (stage.ParserResult, bool) {
|
||||||
stdout := executorResult.Files[conf.Stdout]
|
stdout := executorResult.Files[conf.Stdout]
|
||||||
stderr := executorResult.Files[conf.Stderr]
|
stderr := executorResult.Files[conf.Stderr]
|
||||||
|
|
|
@ -1,9 +1,26 @@
|
||||||
|
// Package keyword implements keyword-based output analysis functionality.
|
||||||
|
// It evaluates output files by searching for specific keywords and assigns scores based on matches.
|
||||||
package keyword
|
package keyword
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "keyword"
|
var name = "keyword"
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Keywords []string
|
||||||
|
Score int
|
||||||
|
MaxMatchCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Files []string
|
||||||
|
ForceQuitOnDeduct bool `default:"false"`
|
||||||
|
Matches []Match
|
||||||
|
}
|
||||||
|
|
||||||
|
type Keyword struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Keyword{})
|
stage.RegisterParser(name, &Keyword{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Match struct {
|
|
||||||
Keywords []string
|
|
||||||
Score int
|
|
||||||
MaxMatchCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Files []string
|
|
||||||
ForceQuitOnDeduct bool `default:"false"`
|
|
||||||
Matches []Match
|
|
||||||
}
|
|
||||||
|
|
||||||
type Keyword struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
score := conf.Score
|
score := conf.Score
|
||||||
comment := ""
|
comment := ""
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
|
// Package log logs the json key-value pairs from given file. The log can be
|
||||||
|
// used for Loki that contains run time status.
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "log"
|
var name = "log"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
FileName string `default:"stdout"`
|
||||||
|
Msg string `default:"log msg"`
|
||||||
|
Level int `default:"0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Log struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Log{})
|
stage.RegisterParser(name, &Log{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
FileName string `default:"stdout"`
|
|
||||||
Msg string `default:"log msg"`
|
|
||||||
Level int `default:"0"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Log struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
content := executorResult.Files[conf.FileName]
|
content := executorResult.Files[conf.FileName]
|
||||||
var data map[string]any
|
var data map[string]any
|
||||||
|
|
|
@ -1,9 +1,25 @@
|
||||||
|
// Package resultdetail provides detailed execution result output.
|
||||||
package resultdetail
|
package resultdetail
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "result-detail"
|
var name = "result-detail"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
ShowExecutorStatus bool `default:"true"`
|
||||||
|
ShowExitStatus bool `default:"false"`
|
||||||
|
ShowError bool `default:"false"`
|
||||||
|
ShowTime bool `default:"true"`
|
||||||
|
ShowMemory bool `default:"true"`
|
||||||
|
ShowRunTime bool `default:"false"`
|
||||||
|
ShowFiles []string
|
||||||
|
FilesInCodeBlock bool `default:"true"`
|
||||||
|
MaxFileLength int `default:"65536"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResultDetail struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &ResultDetail{})
|
stage.RegisterParser(name, &ResultDetail{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
ShowExecutorStatus bool `default:"true"`
|
|
||||||
ShowExitStatus bool `default:"false"`
|
|
||||||
ShowError bool `default:"false"`
|
|
||||||
ShowTime bool `default:"true"`
|
|
||||||
ShowMemory bool `default:"true"`
|
|
||||||
ShowRunTime bool `default:"false"`
|
|
||||||
ShowFiles []string
|
|
||||||
FilesInCodeBlock bool `default:"true"`
|
|
||||||
MaxFileLength int `default:"65536"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultDetail struct{}
|
|
||||||
|
|
||||||
func (*ResultDetail) Run(results []stage.ExecutorResult, confAny any) (
|
func (*ResultDetail) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
[]stage.ParserResult, bool, error,
|
[]stage.ParserResult, bool, error,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
|
// Package resultstatus provides functionality to parse execution results
|
||||||
|
// and determine success/failure status. It can return forced quit status
|
||||||
|
// when a non-accepted status is encountered.
|
||||||
package resultstatus
|
package resultstatus
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "result-status"
|
var name = "result-status"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Comment string
|
||||||
|
ForceQuitOnNotAccepted bool `default:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResultStatus struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &ResultStatus{})
|
stage.RegisterParser(name, &ResultStatus{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Comment string
|
|
||||||
ForceQuitOnNotAccepted bool `default:"true"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultStatus struct{}
|
|
||||||
|
|
||||||
func (*ResultStatus) Run(results []stage.ExecutorResult, confAny any) (
|
func (*ResultStatus) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
[]stage.ParserResult, bool, error,
|
[]stage.ParserResult, bool, error,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
|
// Package sample provides functionality to parse and process sample outputs
|
||||||
|
// from stdout and stderr of the sample program. Use this as a sample.
|
||||||
package sample
|
package sample
|
||||||
|
|
||||||
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
import "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
|
|
||||||
var name = "sample"
|
var name = "sample"
|
||||||
|
|
||||||
|
type Conf struct {
|
||||||
|
Score int
|
||||||
|
Comment string
|
||||||
|
Stdout string `default:"stdout"`
|
||||||
|
Stderr string `default:"stderr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Sample struct{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
stage.RegisterParser(name, &Sample{})
|
stage.RegisterParser(name, &Sample{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,6 @@ import (
|
||||||
"github.com/joint-online-judge/JOJ3/pkg/sample"
|
"github.com/joint-online-judge/JOJ3/pkg/sample"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
Score int
|
|
||||||
Comment string
|
|
||||||
Stdout string `default:"stdout"`
|
|
||||||
Stderr string `default:"stderr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Sample struct{}
|
|
||||||
|
|
||||||
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult {
|
||||||
stdout := executorResult.Files[conf.Stdout]
|
stdout := executorResult.Files[conf.Stdout]
|
||||||
// stderr := executorResult.Files[conf.Stderr]
|
// stderr := executorResult.Files[conf.Stderr]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user