|
|
@@ -0,0 +1,133 @@
|
|
|
+package nju.seec.SEECdemo.logic.service.impl.assignment;
|
|
|
+
|
|
|
+import nju.seec.SEECdemo.data.dao.assignment.CodeDAO;
|
|
|
+import nju.seec.SEECdemo.data.dao.assignment.CodeResultDAO;
|
|
|
+import nju.seec.SEECdemo.data.entity.assignment.Code;
|
|
|
+import nju.seec.SEECdemo.data.entity.assignment.CodeResult;
|
|
|
+import nju.seec.SEECdemo.logic.service.ProjectService;
|
|
|
+import nju.seec.SEECdemo.logic.service.impl.assignment.mock.MockGroup;
|
|
|
+import nju.seec.SEECdemo.logic.api.GitlabApi;
|
|
|
+import nju.seec.SEECdemo.logic.api.JenkinsApi;
|
|
|
+import nju.seec.SEECdemo.logic.service.impl.assignment.mock.MockQuestion;
|
|
|
+import nju.seec.SEECdemo.logic.service.impl.assignment.stub.GroupServiceStub;
|
|
|
+import nju.seec.SEECdemo.logic.service.impl.assignment.stub.QuestionServiceStub;
|
|
|
+import nju.seec.SEECdemo.logic.storage.StorageProvider;
|
|
|
+import nju.seec.SEECdemo.util.ApplicationProperties;
|
|
|
+import nju.seec.SEECdemo.util.ToolKit;
|
|
|
+import nju.seec.SEECdemo.util.enums.AssignmentStatus;
|
|
|
+import org.apache.commons.io.FileUtils;
|
|
|
+import org.eclipse.jgit.api.errors.GitAPIException;
|
|
|
+import org.gitlab4j.api.GitLabApiException;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.zeroturnaround.zip.ZipUtil;
|
|
|
+
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.util.Date;
|
|
|
+
|
|
|
+@Component
|
|
|
+public class AssignmentPaperBuilder {
|
|
|
+
|
|
|
+ private static final String TEMP_PREFIX = "MOOCODER-PAPER-";
|
|
|
+ private final GitlabApi gitlabApi;
|
|
|
+ private final GitHelper helper;
|
|
|
+ private final JenkinsApi jenkinsApi;
|
|
|
+ private final CodeDAO codeDAO;
|
|
|
+ private final CodeResultDAO codeResultDAO;
|
|
|
+ private final StorageProvider storageProvider;
|
|
|
+
|
|
|
+ private final QuestionServiceStub questionServiceStub;
|
|
|
+ private final GroupServiceStub groupServiceStub;
|
|
|
+ private final ProjectService projectService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ public AssignmentPaperBuilder(GitlabApi gitlabApi, GitHelper helper, JenkinsApi jenkinsApi, CodeDAO codeDAO, CodeResultDAO codeResultDAO, StorageProvider storageProvider,
|
|
|
+ QuestionServiceStub questionServiceStub, GroupServiceStub groupServiceStub, ProjectService projectService){
|
|
|
+ this.gitlabApi = gitlabApi;
|
|
|
+ this.helper = helper;
|
|
|
+ this.jenkinsApi = jenkinsApi;
|
|
|
+ this.codeDAO = codeDAO;
|
|
|
+ this.codeResultDAO = codeResultDAO;
|
|
|
+ this.storageProvider = storageProvider;
|
|
|
+ this.questionServiceStub = questionServiceStub;
|
|
|
+ this.groupServiceStub = groupServiceStub;
|
|
|
+ this.projectService = projectService;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void buildCodePaper(Code code) throws IOException, GitAPIException, GitLabApiException {
|
|
|
+ File tempDir = Files.createTempDirectory(TEMP_PREFIX).toFile();
|
|
|
+ try {
|
|
|
+ code.setId(gitlabApi.createProject(code.getUuid()));
|
|
|
+ releaseQuestion(code.getQuestionId(), tempDir);
|
|
|
+ code.setInitHash(helper.push(tempDir, code.getUuid()));
|
|
|
+ } catch (GitAPIException | GitLabApiException e) {
|
|
|
+ code.setStatus(AssignmentStatus.UNAVAILABLE);
|
|
|
+ throw e;
|
|
|
+ } finally {
|
|
|
+ FileUtils.deleteDirectory(tempDir);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void addGroupsToPaper(int codeId) {
|
|
|
+ Code code = codeDAO.findById(codeId);
|
|
|
+ if (code.getStatus() != AssignmentStatus.PREPARING) return;
|
|
|
+ // 为群组创建项目,并将组员加入到项目中
|
|
|
+ try {
|
|
|
+ for(MockGroup group: groupServiceStub.getGroupListByCourse(code.getCourseId())){
|
|
|
+ addGroupToPaper(code, group);
|
|
|
+ }
|
|
|
+ code.setStatus(AssignmentStatus.AVAILABLE);
|
|
|
+ } catch (IOException | GitLabApiException e) {
|
|
|
+ System.out.println("将小组加入作业时发生异常" + ToolKit.format(e));
|
|
|
+ code.setStatus(AssignmentStatus.UNAVAILABLE);
|
|
|
+ }
|
|
|
+ codeDAO.save(code);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addGroupToPaper(Code code, MockGroup group) throws IOException, GitLabApiException {
|
|
|
+ // fork项目的时候,将项目设置成private的,因为组员设置成了Master权限,而只有组的Owner才能够更项目可见性
|
|
|
+ // (private、internal、public),所以此处用root用户来fork
|
|
|
+ int projectId = gitlabApi.forkProject(gitlabApi.getRootUserId(), code.getId(), group.getNamespace());
|
|
|
+ CodeResult codeResult = new CodeResult();
|
|
|
+ codeResult.setId(projectId);
|
|
|
+ codeResult.setGroupId(group.getId());
|
|
|
+ codeResult.setCode(code);
|
|
|
+ // TODO
|
|
|
+ // 创建jenkins上的构建job
|
|
|
+ String buildJob = projectId + "-build";
|
|
|
+ jenkinsApi.createBuildJob(buildJob);
|
|
|
+ codeResult.setBuildJob(buildJob);
|
|
|
+ // 调用kube Api创建该项目的部署空间,并记录其id
|
|
|
+ Long projectDeployNameSpace = projectService.createSeecIIProject(formProjectName(group.getId(), code.getId()),
|
|
|
+ "", // 暂时留空
|
|
|
+ Date.from(code.getStartAt().atZone(ZoneId.systemDefault()).toInstant()),
|
|
|
+ Date.from(code.getEndAt().atZone(ZoneId.systemDefault()).toInstant()));
|
|
|
+ codeResult.setDeployNamespace(projectDeployNameSpace);
|
|
|
+ // 创建jenkins上的测试job
|
|
|
+ String testJob = projectId + "-test";
|
|
|
+ jenkinsApi.createTestJob(testJob);
|
|
|
+ codeResult.setTestJob(testJob);
|
|
|
+ codeResultDAO.save(codeResult);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void releaseQuestion(Long questionId, File codeDir) throws IOException {
|
|
|
+ FileUtils.cleanDirectory(codeDir);
|
|
|
+ MockQuestion question = questionServiceStub.getQuestion(questionId);
|
|
|
+ byte[] content = storageProvider.fetch(question.getUniqueName() + ".zip");
|
|
|
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
|
|
|
+ ZipUtil.unpack(inputStream, codeDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String formProjectName(int groupId, int codeWorkId){
|
|
|
+ return groupId + "c" + codeWorkId;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|