Merge branch 'master' into commit-parser
This commit is contained in:
commit
9d3a980272
60
README.md
60
README.md
|
@ -22,7 +22,7 @@ $ # make sure you are in go-judge directory
|
||||||
$ ./tmp/go-judge -http-addr 0.0.0.0:5050 -grpc-addr 0.0.0.0:5051 -monitor-addr 0.0.0.0:5052 -enable-grpc -enable-debug -enable-metrics
|
$ ./tmp/go-judge -http-addr 0.0.0.0:5050 -grpc-addr 0.0.0.0:5051 -monitor-addr 0.0.0.0:5052 -enable-grpc -enable-debug -enable-metrics
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Pull submodules. It might be slow, so only run it when necessary.
|
6. Pull submodules. It might be slow, so only run it when the test branches are out of date.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ # make sure you are in JOJ3 directory
|
$ # make sure you are in JOJ3 directory
|
||||||
|
@ -75,7 +75,7 @@ Check `Cmd` at <https://github.com/criyle/go-judge#rest-api-interface>.
|
||||||
|
|
||||||
Some difference:
|
Some difference:
|
||||||
|
|
||||||
- `CopyInCwd bool`: set to `true` to add everything in the current working directory to `CopyIn`.
|
- `CopyInDir string`: set to non-empty string to add everything in that directory to `CopyIn`.
|
||||||
- `CopyInCached map[string]string`: key: file name in the sandbox, value: file name used in `CopyOutCached`.
|
- `CopyInCached map[string]string`: key: file name in the sandbox, value: file name used in `CopyOutCached`.
|
||||||
- `LocalFile`: now supports the relative path
|
- `LocalFile`: now supports the relative path
|
||||||
|
|
||||||
|
@ -88,6 +88,12 @@ Check the `Result` at <https://github.com/criyle/go-judge#rest-api-interface>.
|
||||||
- `Score int`: score of the stage.
|
- `Score int`: score of the stage.
|
||||||
- `Comment string`: comment on the stage.
|
- `Comment string`: comment on the stage.
|
||||||
|
|
||||||
|
## Binaries (under `/cmd` and `/pkg`)
|
||||||
|
|
||||||
|
### Sample
|
||||||
|
|
||||||
|
Just a sample on how to write an executable that can be called by the executor.
|
||||||
|
|
||||||
### HealthCheck
|
### HealthCheck
|
||||||
|
|
||||||
The repohealth check will return a json list to for check result. The structure follows the score-comment pattern.
|
The repohealth check will return a json list to for check result. The structure follows the score-comment pattern.
|
||||||
|
@ -95,3 +101,53 @@ The repohealth check will return a json list to for check result. The structure
|
||||||
HealthCheck currently includes, `reposize`, `forbidden file`, `Metafile existence`, `non-ascii character` in file and message, `release tag`, and `ci files invariance` check.
|
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.
|
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.
|
||||||
|
|
||||||
|
## 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`.)
|
||||||
|
|
||||||
|
### 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.
|
||||||
|
|
|
@ -85,22 +85,6 @@ func parseConfFile(path string, jobtype JobType) (conf Conf, err error) {
|
||||||
slog.Error("parse stages conf", "error", err)
|
slog.Error("parse stages conf", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = d.Validate(&conf); err != nil {
|
|
||||||
slog.Error("validate stages conf", "error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredStages := []Stage{}
|
|
||||||
|
|
||||||
for _, stage := range conf.Stages {
|
|
||||||
if filterStage(stage, jobtype) {
|
|
||||||
filteredStages = append(filteredStages, stage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.Stages = filteredStages
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ func convertPBCmd(cmd []stage.Cmd) []*pb.Request_CmdType {
|
||||||
CpuSetLimit: c.CPUSetLimit,
|
CpuSetLimit: c.CPUSetLimit,
|
||||||
DataSegmentLimit: c.DataSegmentLimit,
|
DataSegmentLimit: c.DataSegmentLimit,
|
||||||
AddressSpaceLimit: c.AddressSpaceLimit,
|
AddressSpaceLimit: c.AddressSpaceLimit,
|
||||||
CopyIn: convertPBCopyIn(c.CopyIn, c.CopyInCwd),
|
CopyIn: convertPBCopyIn(c.CopyIn, c.CopyInDir),
|
||||||
CopyOut: convertPBCopyOut(c.CopyOut),
|
CopyOut: convertPBCopyOut(c.CopyOut),
|
||||||
CopyOutCached: convertPBCopyOut(c.CopyOutCached),
|
CopyOutCached: convertPBCopyOut(c.CopyOutCached),
|
||||||
CopyOutMax: c.CopyOutMax,
|
CopyOutMax: c.CopyOutMax,
|
||||||
|
@ -39,9 +39,11 @@ func convertPBCmd(cmd []stage.Cmd) []*pb.Request_CmdType {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertPBCopyIn(copyIn map[string]stage.CmdFile, copyInCwd bool) map[string]*pb.Request_File {
|
func convertPBCopyIn(
|
||||||
if copyInCwd {
|
copyIn map[string]stage.CmdFile, copyInDir string,
|
||||||
_ = filepath.Walk(".",
|
) map[string]*pb.Request_File {
|
||||||
|
if copyInDir != "" {
|
||||||
|
_ = filepath.Walk(copyInDir,
|
||||||
func(path string, info os.FileInfo, err error) error {
|
func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -29,7 +29,7 @@ func severityFromString(severityString string) (Severity, error) {
|
||||||
case "information":
|
case "information":
|
||||||
return INFORMATION, nil
|
return INFORMATION, nil
|
||||||
default:
|
default:
|
||||||
return UNKNOWN, fmt.Errorf("unkown severity type \"%s\" for cppcheck", severityString)
|
return UNKNOWN, fmt.Errorf("unknown severity type \"%s\" for cppcheck", severityString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ type Cmd struct {
|
||||||
|
|
||||||
CopyIn map[string]CmdFile `json:"copyIn"`
|
CopyIn map[string]CmdFile `json:"copyIn"`
|
||||||
CopyInCached map[string]string `json:"copyInCached"`
|
CopyInCached map[string]string `json:"copyInCached"`
|
||||||
CopyInCwd bool `json:"copyInCwd"`
|
CopyInDir string `json:"copyInDir"`
|
||||||
|
|
||||||
CopyOut []string `json:"copyOut"`
|
CopyOut []string `json:"copyOut"`
|
||||||
CopyOutCached []string `json:"copyOutCached"`
|
CopyOutCached []string `json:"copyOutCached"`
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5"
|
"github.com/go-git/go-git/v5"
|
||||||
"github.com/go-git/go-git/v5/plumbing/object"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// nonAsciiMsg checks for non-ASCII characters in the commit message.
|
// nonAsciiMsg checks for non-ASCII characters in the commit message.
|
||||||
|
@ -28,23 +27,19 @@ func NonAsciiMsg(root string) error {
|
||||||
slog.Error("getting reference", "err", err)
|
slog.Error("getting reference", "err", err)
|
||||||
return fmt.Errorf("error getting reference: %v", err)
|
return fmt.Errorf("error getting reference: %v", err)
|
||||||
}
|
}
|
||||||
commits, err := repo.Log(&git.LogOptions{From: ref.Hash()})
|
|
||||||
|
commit, err := repo.CommitObject(ref.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("getting commits", "err", err)
|
slog.Error("getting latest commit", "err", err)
|
||||||
return fmt.Errorf("error getting commits from reference %s: %v", ref.Hash(), err)
|
return fmt.Errorf("error getting latest commit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var msgs []string
|
msg := commit.Message
|
||||||
err = commits.ForEach(func(c *object.Commit) error {
|
if msg == "" {
|
||||||
msgs = append(msgs, c.Message)
|
|
||||||
return nil
|
return nil
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("iterating commits", "err", err)
|
|
||||||
return fmt.Errorf("error iterating commits: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var nonAsciiMsgs []string
|
var isCommitLegal bool = true
|
||||||
// List of prefixes to ignore in the commit message
|
// List of prefixes to ignore in the commit message
|
||||||
ignoredPrefixes := []string{
|
ignoredPrefixes := []string{
|
||||||
"Co-authored-by:",
|
"Co-authored-by:",
|
||||||
|
@ -53,35 +48,31 @@ func NonAsciiMsg(root string) error {
|
||||||
"Reviewed-on:",
|
"Reviewed-on:",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, msg := range msgs {
|
// Split message by lines and ignore specific lines with prefixes
|
||||||
if msg == "" {
|
lines := strings.Split(msg, "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
trimmedLine := strings.TrimSpace(line)
|
||||||
|
ignore := false
|
||||||
|
for _, prefix := range ignoredPrefixes {
|
||||||
|
if strings.HasPrefix(trimmedLine, prefix) {
|
||||||
|
ignore = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ignore {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Split message by lines and ignore specific lines with prefixes
|
// Check for non-ASCII characters in the rest of the lines
|
||||||
lines := strings.Split(msg, "\n")
|
for _, c := range line {
|
||||||
for _, line := range lines {
|
if c > unicode.MaxASCII {
|
||||||
trimmedLine := strings.TrimSpace(line)
|
isCommitLegal = false
|
||||||
ignore := false
|
break
|
||||||
for _, prefix := range ignoredPrefixes {
|
|
||||||
if strings.HasPrefix(trimmedLine, prefix) {
|
|
||||||
ignore = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ignore {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Check for non-ASCII characters in the rest of the lines
|
|
||||||
for _, c := range line {
|
|
||||||
if c > unicode.MaxASCII {
|
|
||||||
nonAsciiMsgs = append(nonAsciiMsgs, msg)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(nonAsciiMsgs) > 0 {
|
|
||||||
return fmt.Errorf("Non-ASCII characters in commit messages:\n%s", strings.Join(nonAsciiMsgs, "\n"))
|
if !isCommitLegal {
|
||||||
|
return fmt.Errorf("Non-ASCII characters in commit messages:\n%s", msg)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ func getMetas(rootDir string, fileList []string) ([]string, string, error) {
|
||||||
matched := false
|
matched := false
|
||||||
umatchedRes := ""
|
umatchedRes := ""
|
||||||
|
|
||||||
// TODO: it seems that there is no good find subsitution now
|
// TODO: it seems that there is no good find substitution now
|
||||||
// modify current code if exist a better solution
|
// modify current code if exist a better solution
|
||||||
for i, regex := range regexList {
|
for i, regex := range regexList {
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
|
|
|
@ -18,14 +18,14 @@ for submodule in $submodules; do
|
||||||
else
|
else
|
||||||
cd $repo_dir
|
cd $repo_dir
|
||||||
git fetch --all
|
git fetch --all
|
||||||
cd -
|
cd - > /dev/null
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
repo_names[$repo_name]=1
|
repo_names[$repo_name]=1
|
||||||
cd $repo_dir
|
cd $repo_dir
|
||||||
git checkout -q $branch
|
git checkout -q $branch
|
||||||
git reset -q --hard origin/$branch
|
git reset -q --hard origin/$branch
|
||||||
cd -
|
cd - > /dev/null
|
||||||
submodule_dir="$submodules_dir/$repo_name/$submodule"
|
submodule_dir="$submodules_dir/$repo_name/$submodule"
|
||||||
mkdir -p $submodule_dir
|
mkdir -p $submodule_dir
|
||||||
cp -rT $repo_dir $submodule_dir
|
cp -rT $repo_dir $submodule_dir
|
||||||
|
|
|
@ -17,5 +17,5 @@ for submodule in $submodules; do
|
||||||
mv -f "joj3_result.json" "expected.json"
|
mv -f "joj3_result.json" "expected.json"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
cd -
|
cd - > /dev/null
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in New Issue
Block a user