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
	 zzjc1234
						zzjc1234