feat(cmd/joj3): extra summary info from teapot [force build]
This commit is contained in:
		
							parent
							
								
									7b4d167448
								
							
						
					
					
						commit
						e4bfcfbe8d
					
				|  | @ -9,6 +9,7 @@ import ( | ||||||
| 	"github.com/joint-online-judge/JOJ3/cmd/joj3/conf" | 	"github.com/joint-online-judge/JOJ3/cmd/joj3/conf" | ||||||
| 	"github.com/joint-online-judge/JOJ3/cmd/joj3/stage" | 	"github.com/joint-online-judge/JOJ3/cmd/joj3/stage" | ||||||
| 	"github.com/joint-online-judge/JOJ3/cmd/joj3/teapot" | 	"github.com/joint-online-judge/JOJ3/cmd/joj3/teapot" | ||||||
|  | 	internalStage "github.com/joint-online-judge/JOJ3/internal/stage" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
|  | @ -31,7 +32,37 @@ func init() { | ||||||
| 	showVersion = flag.Bool("version", false, "print current version") | 	showVersion = flag.Bool("version", false, "print current version") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func mainImpl() error { | func mainImpl() (err error) { | ||||||
|  | 	confObj := new(conf.Conf) | ||||||
|  | 	var stageResults []internalStage.StageResult | ||||||
|  | 	var stageForceQuit bool | ||||||
|  | 	var teapotResult teapot.TeapotResult | ||||||
|  | 	defer func() { | ||||||
|  | 		actor := os.Getenv("GITHUB_ACTOR") | ||||||
|  | 		repository := os.Getenv("GITHUB_REPOSITORY") | ||||||
|  | 		ref := os.Getenv("GITHUB_REF") | ||||||
|  | 		workflow := os.Getenv("GITHUB_WORKFLOW") | ||||||
|  | 		totalScore := 0 | ||||||
|  | 		for _, stageResult := range stageResults { | ||||||
|  | 			for _, result := range stageResult.Results { | ||||||
|  | 				totalScore += result.Score | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		slog.Info( | ||||||
|  | 			"joj3 summary", | ||||||
|  | 			"name", confObj.Name, | ||||||
|  | 			"totalScore", totalScore, | ||||||
|  | 			"forceQuit", stageForceQuit, | ||||||
|  | 			"actor", actor, | ||||||
|  | 			"repository", repository, | ||||||
|  | 			"ref", ref, | ||||||
|  | 			"workflow", workflow, | ||||||
|  | 			"issue", teapotResult.Issue, | ||||||
|  | 			"action", teapotResult.Action, | ||||||
|  | 			"sha", teapotResult.Sha, | ||||||
|  | 			"error", err, | ||||||
|  | 		) | ||||||
|  | 	}() | ||||||
| 	if err := setupSlog(""); err != nil { // before conf is loaded
 | 	if err := setupSlog(""); err != nil { // before conf is loaded
 | ||||||
| 		slog.Error("setup slog", "error", err) | 		slog.Error("setup slog", "error", err) | ||||||
| 		return err | 		return err | ||||||
|  | @ -57,7 +88,7 @@ func mainImpl() error { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	slog.Info("try to load conf", "path", confPath) | 	slog.Info("try to load conf", "path", confPath) | ||||||
| 	confObj, err := conf.ParseConfFile(confPath) | 	confObj, err = conf.ParseConfFile(confPath) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		slog.Error("parse conf", "error", err) | 		slog.Error("parse conf", "error", err) | ||||||
| 		return err | 		return err | ||||||
|  | @ -79,16 +110,16 @@ func mainImpl() error { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	groups := conf.MatchGroups(confObj, conventionalCommit) | 	groups := conf.MatchGroups(confObj, conventionalCommit) | ||||||
| 	stageResults, stageForceQuit, err := stage.Run(confObj, groups) | 	stageResults, stageForceQuit, err = stage.Run(confObj, groups) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		slog.Error("stage run", "error", err) | 		slog.Error("stage run", "error", err) | ||||||
| 	} | 	} | ||||||
| 	stage.Summarize(confObj, stageResults, stageForceQuit) |  | ||||||
| 	if err = stage.Write(confObj.Stage.OutputPath, stageResults); err != nil { | 	if err = stage.Write(confObj.Stage.OutputPath, stageResults); err != nil { | ||||||
| 		slog.Error("stage write", "error", err) | 		slog.Error("stage write", "error", err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if err := teapot.Run(confObj, runID); err != nil { | 	teapotResult, err = teapot.Run(confObj, runID) | ||||||
|  | 	if err != nil { | ||||||
| 		slog.Error("teapot run", "error", err) | 		slog.Error("teapot run", "error", err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -13,6 +13,8 @@ import ( | ||||||
| 	"github.com/jinzhu/copier" | 	"github.com/jinzhu/copier" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | type StageResult stage.StageResult | ||||||
|  | 
 | ||||||
| func generateStages(conf *conf.Conf, groups []string) ([]stage.Stage, error) { | func generateStages(conf *conf.Conf, groups []string) ([]stage.Stage, error) { | ||||||
| 	stages := []stage.Stage{} | 	stages := []stage.Stage{} | ||||||
| 	existNames := map[string]bool{} | 	existNames := map[string]bool{} | ||||||
|  |  | ||||||
|  | @ -1,34 +0,0 @@ | ||||||
| package stage |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"log/slog" |  | ||||||
| 	"os" |  | ||||||
| 
 |  | ||||||
| 	"github.com/joint-online-judge/JOJ3/cmd/joj3/conf" |  | ||||||
| 	"github.com/joint-online-judge/JOJ3/internal/stage" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func Summarize( |  | ||||||
| 	conf *conf.Conf, stageResults []stage.StageResult, stageForceQuit bool, |  | ||||||
| ) { |  | ||||||
| 	actor := os.Getenv("GITHUB_ACTOR") |  | ||||||
| 	repository := os.Getenv("GITHUB_REPOSITORY") |  | ||||||
| 	ref := os.Getenv("GITHUB_REF") |  | ||||||
| 	workflow := os.Getenv("GITHUB_WORKFLOW") |  | ||||||
| 	totalScore := 0 |  | ||||||
| 	for _, stageResult := range stageResults { |  | ||||||
| 		for _, result := range stageResult.Results { |  | ||||||
| 			totalScore += result.Score |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	slog.Info( |  | ||||||
| 		"stage summary", |  | ||||||
| 		"name", conf.Name, |  | ||||||
| 		"totalScore", totalScore, |  | ||||||
| 		"forceQuit", stageForceQuit, |  | ||||||
| 		"actor", actor, |  | ||||||
| 		"repository", repository, |  | ||||||
| 		"ref", ref, |  | ||||||
| 		"workflow", workflow, |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
|  | @ -2,6 +2,8 @@ package teapot | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
| 	"os" | 	"os" | ||||||
|  | @ -14,7 +16,13 @@ import ( | ||||||
| 	"github.com/joint-online-judge/JOJ3/cmd/joj3/conf" | 	"github.com/joint-online-judge/JOJ3/cmd/joj3/conf" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Run(conf *conf.Conf, runID string) error { | type TeapotResult struct { | ||||||
|  | 	Issue  int    `json:"issue"` | ||||||
|  | 	Action int    `json:"action"` | ||||||
|  | 	Sha    string `json:"sha"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Run(conf *conf.Conf, runID string) (teapotResult TeapotResult, err error) { | ||||||
| 	os.Setenv("LOG_FILE_PATH", conf.Teapot.LogPath) | 	os.Setenv("LOG_FILE_PATH", conf.Teapot.LogPath) | ||||||
| 	os.Setenv("_TYPER_STANDARD_TRACEBACK", "1") | 	os.Setenv("_TYPER_STANDARD_TRACEBACK", "1") | ||||||
| 	sha := os.Getenv("GITHUB_SHA") | 	sha := os.Getenv("GITHUB_SHA") | ||||||
|  | @ -24,52 +32,11 @@ func Run(conf *conf.Conf, runID string) error { | ||||||
| 	if actor == "" || repository == "" || strings.Count(repository, "/") != 1 || | 	if actor == "" || repository == "" || strings.Count(repository, "/") != 1 || | ||||||
| 		runNumber == "" { | 		runNumber == "" { | ||||||
| 		slog.Error("teapot env not set") | 		slog.Error("teapot env not set") | ||||||
| 		return fmt.Errorf("teapot env not set") | 		err = fmt.Errorf("teapot env not set") | ||||||
|  | 		return | ||||||
| 	} | 	} | ||||||
| 	repoParts := strings.Split(repository, "/") | 	repoParts := strings.Split(repository, "/") | ||||||
| 	repoName := repoParts[1] | 	repoName := repoParts[1] | ||||||
| 	re := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) |  | ||||||
| 	execCommand := func(name string, cmdArgs []string) error { |  | ||||||
| 		cmd := exec.Command(name, cmdArgs...) // #nosec G204
 |  | ||||||
| 		stderr, err := cmd.StderrPipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			slog.Error("stderr pipe", "error", err) |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		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(name, "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 err |  | ||||||
| 		} |  | ||||||
| 		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 err |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	skipIssueArg := "--no-skip-result-issue" | 	skipIssueArg := "--no-skip-result-issue" | ||||||
| 	if conf.Teapot.SkipIssue { | 	if conf.Teapot.SkipIssue { | ||||||
| 		skipIssueArg = "--skip-result-issue" | 		skipIssueArg = "--skip-result-issue" | ||||||
|  | @ -86,7 +53,8 @@ func Run(conf *conf.Conf, runID string) error { | ||||||
| 	if conf.Teapot.SubmitterInIssueTitle { | 	if conf.Teapot.SubmitterInIssueTitle { | ||||||
| 		submitterInIssueTitleArg = "--submitter-in-issue-title" | 		submitterInIssueTitleArg = "--submitter-in-issue-title" | ||||||
| 	} | 	} | ||||||
| 	if err := execCommand("joint-teapot", []string{ | 	re := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) | ||||||
|  | 	cmd := exec.Command("joint-teapot", | ||||||
| 		"joj3-all", conf.Teapot.EnvFilePath, conf.Stage.OutputPath, actor, | 		"joj3-all", conf.Teapot.EnvFilePath, conf.Stage.OutputPath, actor, | ||||||
| 		conf.Teapot.GradingRepoName, repoName, runNumber, | 		conf.Teapot.GradingRepoName, repoName, runNumber, | ||||||
| 		conf.Teapot.ScoreboardPath, conf.Teapot.FailedTablePath, | 		conf.Teapot.ScoreboardPath, conf.Teapot.FailedTablePath, | ||||||
|  | @ -94,9 +62,51 @@ func Run(conf *conf.Conf, runID string) error { | ||||||
| 		"--max-total-score", strconv.Itoa(conf.Teapot.MaxTotalScore), | 		"--max-total-score", strconv.Itoa(conf.Teapot.MaxTotalScore), | ||||||
| 		skipIssueArg, skipScoreboardArg, | 		skipIssueArg, skipScoreboardArg, | ||||||
| 		skipFailedTableArg, submitterInIssueTitleArg, | 		skipFailedTableArg, submitterInIssueTitleArg, | ||||||
| 	}); err != nil { | 	) // #nosec G204
 | ||||||
| 		slog.Error("teapot exit", "error", err) | 	stdoutBuf := new(bytes.Buffer) | ||||||
| 		return fmt.Errorf("teapot exit") | 	cmd.Stdout = stdoutBuf | ||||||
|  | 	stderr, err := cmd.StderrPipe() | ||||||
|  | 	if err != nil { | ||||||
|  | 		slog.Error("stderr pipe", "error", err) | ||||||
|  | 		return | ||||||
| 	} | 	} | ||||||
| 	return nil | 	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 | ||||||
|  | 	} | ||||||
|  | 	if json.Unmarshal(stdoutBuf.Bytes(), &teapotResult) != nil { | ||||||
|  | 		slog.Error("unmarshal teapot result", "error", err, | ||||||
|  | 			"stdout", stdoutBuf.String()) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	slog.Info("teapot result", "result", teapotResult) | ||||||
|  | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user