feat(cmd/joj3): remove hardcoded teapot part (#83) [force build]
This commit is contained in:
parent
290b614159
commit
10ff3ebfa1
|
@ -95,12 +95,6 @@ These steps are executed in runner-images. We use `sudo -u tt` to elevate the pe
|
|||
- The parser can return a force quit, which means all the stages after it will be skipped, but the remaining parsers in the current stage will run.
|
||||
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.
|
||||
2. Run Joint-Teapot.
|
||||
1. Generally speaking, it reads the JOJ3 results file and output results on Gitea.
|
||||
2. With `joint-teapot joj3-all`, it will do the following things:
|
||||
1. Create/Edit an issue in the submitter's repo to show the results.
|
||||
2. Update the scoreboard file in grading repo.
|
||||
3. Update the failed table file in grading repo.
|
||||
|
||||
## Components
|
||||
|
||||
|
|
34
cmd/joj3/env/env.go
vendored
34
cmd/joj3/env/env.go
vendored
|
@ -7,23 +7,27 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ConfName = "JOJ3_CONF_NAME"
|
||||
Groups = "JOJ3_GROUPS"
|
||||
RunID = "JOJ3_RUN_ID"
|
||||
ConfName = "JOJ3_CONF_NAME"
|
||||
Groups = "JOJ3_GROUPS"
|
||||
RunID = "JOJ3_RUN_ID"
|
||||
CommitMsg = "JOJ3_COMMIT_MSG"
|
||||
ForceQuitStageName = "JOJ3_FORCE_QUIT_STAGE_NAME"
|
||||
)
|
||||
|
||||
type Attribute struct {
|
||||
ConfName string
|
||||
Groups string
|
||||
RunID string
|
||||
Actor string
|
||||
Repository string
|
||||
Sha string
|
||||
Ref string
|
||||
Workflow string
|
||||
RunNumber string
|
||||
ActorName string
|
||||
ActorID string
|
||||
ConfName string
|
||||
CommitMsg string
|
||||
Groups string
|
||||
RunID string
|
||||
Actor string
|
||||
Repository string
|
||||
Sha string
|
||||
Ref string
|
||||
Workflow string
|
||||
RunNumber string
|
||||
ActorName string
|
||||
ActorID string
|
||||
ForceQuitStageName string
|
||||
}
|
||||
|
||||
var Attr Attribute
|
||||
|
@ -51,4 +55,6 @@ func Set() {
|
|||
os.Setenv(ConfName, Attr.ConfName)
|
||||
os.Setenv(Groups, Attr.Groups)
|
||||
os.Setenv(RunID, Attr.RunID)
|
||||
os.Setenv(CommitMsg, Attr.CommitMsg)
|
||||
os.Setenv(ForceQuitStageName, Attr.ForceQuitStageName)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
|
||||
"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/teapot"
|
||||
"github.com/joint-online-judge/JOJ3/internal/conf"
|
||||
internalStage "github.com/joint-online-judge/JOJ3/internal/stage"
|
||||
)
|
||||
|
@ -33,36 +32,7 @@ func init() {
|
|||
|
||||
func mainImpl() (err error) {
|
||||
confObj := new(conf.Conf)
|
||||
var stageResults []internalStage.StageResult
|
||||
var forceQuitStageName string
|
||||
var teapotRunResult teapot.RunResult
|
||||
var commitMsg string
|
||||
|
||||
// summarize
|
||||
defer func() {
|
||||
totalScore := 0
|
||||
for _, stageResult := range stageResults {
|
||||
for _, result := range stageResult.Results {
|
||||
totalScore += result.Score
|
||||
}
|
||||
}
|
||||
cappedTotalScore := totalScore
|
||||
if confObj.MaxTotalScore >= 0 {
|
||||
cappedTotalScore = min(totalScore, confObj.MaxTotalScore)
|
||||
}
|
||||
slog.Info(
|
||||
"joj3 summary",
|
||||
"totalScore", totalScore,
|
||||
"cappedTotalScore", cappedTotalScore,
|
||||
"forceQuit", forceQuitStageName != "",
|
||||
"forceQuitStageName", forceQuitStageName,
|
||||
"issue", teapotRunResult.Issue,
|
||||
"action", teapotRunResult.Action,
|
||||
"sha", teapotRunResult.Sha,
|
||||
"commitMsg", commitMsg,
|
||||
"error", err,
|
||||
)
|
||||
}()
|
||||
if err := setupSlog(confObj); err != nil { // before conf is loaded
|
||||
slog.Error("setup slog", "error", err)
|
||||
return err
|
||||
|
@ -78,11 +48,12 @@ func mainImpl() (err error) {
|
|||
fallbackConfFileName = confFileName
|
||||
}
|
||||
slog.Info("start joj3", "version", Version)
|
||||
commitMsg, err = conf.GetCommitMsg()
|
||||
commitMsg, err := conf.GetCommitMsg()
|
||||
if err != nil {
|
||||
slog.Error("get commit msg", "error", err)
|
||||
return err
|
||||
}
|
||||
env.Attr.CommitMsg = commitMsg
|
||||
confPath, confStat, conventionalCommit, err := conf.GetConfPath(
|
||||
confFileRoot, confFileName, fallbackConfFileName, commitMsg, tag)
|
||||
if err != nil {
|
||||
|
@ -118,20 +89,20 @@ func mainImpl() (err error) {
|
|||
// run stages
|
||||
groups := conf.MatchGroups(confObj, conventionalCommit)
|
||||
env.Attr.Groups = strings.Join(groups, ",")
|
||||
env.Set()
|
||||
stageResults, forceQuitStageName, err = stage.Run(
|
||||
confObj, groups,
|
||||
_, forceQuitStageName, err := stage.Run(
|
||||
confObj,
|
||||
groups,
|
||||
func(
|
||||
stageResults []internalStage.StageResult,
|
||||
forceQuitStageName string,
|
||||
) {
|
||||
env.Attr.ForceQuitStageName = forceQuitStageName
|
||||
env.Set()
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error("stage run", "error", err)
|
||||
}
|
||||
|
||||
// run teapot
|
||||
teapotRunResult, err = teapot.Run(confObj)
|
||||
if err != nil {
|
||||
slog.Error("teapot run", "error", err)
|
||||
return err
|
||||
}
|
||||
if forceQuitStageName != "" {
|
||||
slog.Info("stage force quit", "name", forceQuitStageName)
|
||||
return fmt.Errorf("stage force quit with name %s", forceQuitStageName)
|
||||
|
|
|
@ -132,7 +132,11 @@ func newErrorStageResults(err error) ([]stage.StageResult, string) {
|
|||
}, "Internal Error"
|
||||
}
|
||||
|
||||
func Run(conf *conf.Conf, groups []string) (
|
||||
func Run(
|
||||
conf *conf.Conf,
|
||||
groups []string,
|
||||
onStagesComplete func([]stage.StageResult, string),
|
||||
) (
|
||||
stageResults []stage.StageResult, forceQuitStageName string, err error,
|
||||
) {
|
||||
executors.InitWithConf(
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package teapot
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func runCommand(args []string) (
|
||||
stdoutBuf *bytes.Buffer, err error,
|
||||
) {
|
||||
re := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
|
||||
cmd := exec.Command("joint-teapot", args...) // #nosec G204
|
||||
stdoutBuf = new(bytes.Buffer)
|
||||
cmd.Stdout = stdoutBuf
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
slog.Error("stderr pipe", "error", err)
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
scanner := bufio.NewScanner(stderr)
|
||||
go func() {
|
||||
for scanner.Scan() {
|
||||
text := re.ReplaceAllString(scanner.Text(), "")
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
slog.Info("joint-teapot", "stderr", text)
|
||||
}
|
||||
wg.Done()
|
||||
if scanner.Err() != nil {
|
||||
slog.Error("stderr scanner", "error", scanner.Err())
|
||||
}
|
||||
}()
|
||||
if err = cmd.Start(); err != nil {
|
||||
slog.Error("cmd start", "error", err)
|
||||
return
|
||||
}
|
||||
wg.Wait()
|
||||
if err = cmd.Wait(); err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
exitCode := exitErr.ExitCode()
|
||||
slog.Error("cmd completed with non-zero exit code",
|
||||
"error", err,
|
||||
"exitCode", exitCode)
|
||||
} else {
|
||||
slog.Error("cmd wait", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package teapot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
||||
"github.com/joint-online-judge/JOJ3/internal/conf"
|
||||
)
|
||||
|
||||
type RunResult struct {
|
||||
Issue int `json:"issue"`
|
||||
Action int `json:"action"`
|
||||
Sha string `json:"sha"`
|
||||
}
|
||||
|
||||
func Run(conf *conf.Conf) (
|
||||
runResult RunResult, err error,
|
||||
) {
|
||||
if conf.Teapot.Skip {
|
||||
slog.Info("teapot skip")
|
||||
return
|
||||
}
|
||||
os.Setenv("LOG_FILE_PATH", conf.Teapot.LogPath)
|
||||
if env.Attr.Actor == "" ||
|
||||
env.Attr.Repository == "" ||
|
||||
strings.Count(env.Attr.Repository, "/") != 1 ||
|
||||
env.Attr.RunNumber == "" {
|
||||
slog.Error("teapot env not set")
|
||||
err = fmt.Errorf("teapot env not set")
|
||||
return
|
||||
}
|
||||
repoParts := strings.Split(env.Attr.Repository, "/")
|
||||
repoName := repoParts[1]
|
||||
skipIssueArg := "--no-skip-result-issue"
|
||||
if conf.Teapot.SkipIssue {
|
||||
skipIssueArg = "--skip-result-issue"
|
||||
}
|
||||
skipScoreboardArg := "--no-skip-scoreboard"
|
||||
if conf.Teapot.SkipScoreboard {
|
||||
skipScoreboardArg = "--skip-scoreboard"
|
||||
}
|
||||
skipFailedTableArg := "--no-skip-failed-table"
|
||||
if conf.Teapot.SkipFailedTable {
|
||||
skipFailedTableArg = "--skip-failed-table"
|
||||
}
|
||||
submitterInIssueTitleArg := "--no-submitter-in-issue-title"
|
||||
if conf.Teapot.SubmitterInIssueTitle {
|
||||
submitterInIssueTitleArg = "--submitter-in-issue-title"
|
||||
}
|
||||
args := []string{
|
||||
"joj3-all", conf.Teapot.EnvFilePath, conf.Stage.OutputPath,
|
||||
env.Attr.Actor, conf.Teapot.GradingRepoName, repoName,
|
||||
env.Attr.RunNumber, conf.Teapot.ScoreboardPath,
|
||||
conf.Teapot.FailedTablePath,
|
||||
conf.Name, env.Attr.Sha, env.Attr.RunID,
|
||||
env.Attr.Groups,
|
||||
"--max-total-score", strconv.Itoa(conf.MaxTotalScore),
|
||||
skipIssueArg, skipScoreboardArg,
|
||||
skipFailedTableArg, submitterInIssueTitleArg,
|
||||
}
|
||||
stdoutBuf, err := runCommand(args)
|
||||
if err != nil {
|
||||
slog.Error("teapot run exec", "error", err)
|
||||
return
|
||||
}
|
||||
if json.Unmarshal(stdoutBuf.Bytes(), &runResult) != nil {
|
||||
slog.Error("unmarshal teapot result", "error", err,
|
||||
"stdout", stdoutBuf.String())
|
||||
return
|
||||
}
|
||||
slog.Info("teapot result", "result", runResult)
|
||||
return
|
||||
}
|
|
@ -44,7 +44,6 @@ var (
|
|||
checkFileNameList string
|
||||
checkFileSumList string
|
||||
metaFile []string
|
||||
confPath string
|
||||
showVersion *bool
|
||||
Version string
|
||||
)
|
||||
|
@ -56,7 +55,6 @@ func init() {
|
|||
flag.StringVar(&checkFileNameList, "checkFileNameList", "", "comma-separated list of files to check")
|
||||
flag.StringVar(&checkFileSumList, "checkFileSumList", "", "comma-separated list of expected checksums")
|
||||
parseMultiValueFlag(&metaFile, "meta", "meta files to check")
|
||||
flag.StringVar(&confPath, "confPath", "", "path to conf file for teapot check") // TODO: remove me
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -40,19 +40,6 @@ type Conf struct {
|
|||
Stages []ConfStage
|
||||
PostStages []ConfStage
|
||||
}
|
||||
Teapot struct {
|
||||
Skip bool `default:"false"`
|
||||
LogPath string `default:"/home/tt/.cache/joint-teapot-debug.log"`
|
||||
EnvFilePath string `default:"/home/tt/.config/teapot/teapot.env"`
|
||||
ScoreboardPath string `default:"scoreboard.csv"`
|
||||
FailedTablePath string `default:"failed-table.md"`
|
||||
GradingRepoName string `default:""`
|
||||
SkipIssue bool `default:"false"`
|
||||
SkipScoreboard bool `default:"false"`
|
||||
SkipFailedTable bool `default:"false"`
|
||||
SubmitterInIssueTitle bool `default:"true"`
|
||||
Groups []ConfGroup
|
||||
}
|
||||
}
|
||||
|
||||
type OptionalCmd struct {
|
||||
|
|
Loading…
Reference in New Issue
Block a user