BuildManager.java 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package com.moekr.moocoder.logic.service.impl;
  2. import com.moekr.moocoder.data.dao.CommitDAO;
  3. import com.moekr.moocoder.data.dao.RecordDAO;
  4. import com.moekr.moocoder.data.dao.ResultDAO;
  5. import com.moekr.moocoder.data.entity.*;
  6. import com.moekr.moocoder.logic.api.JenkinsApi;
  7. import com.moekr.moocoder.logic.api.vo.BuildDetails;
  8. import com.moekr.moocoder.util.ApplicationProperties;
  9. import com.moekr.moocoder.util.ToolKit;
  10. import com.moekr.moocoder.util.enums.BuildStatus;
  11. import com.moekr.moocoder.util.enums.ProblemType;
  12. import com.moekr.moocoder.util.problem.evaluator.Evaluator;
  13. import com.moekr.moocoder.util.problem.helper.ProblemHelper;
  14. import com.offbytwo.jenkins.model.QueueItem;
  15. import lombok.extern.apachecommons.CommonsLog;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.stereotype.Component;
  18. import org.springframework.transaction.annotation.Transactional;
  19. import java.util.HashMap;
  20. import java.util.Map;
  21. @Component
  22. @CommonsLog
  23. public class BuildManager {
  24. private final CommitDAO commitDAO;
  25. private final RecordDAO recordDAO;
  26. private final ResultDAO resultDAO;
  27. private final JenkinsApi jenkinsApi;
  28. private final ApplicationProperties properties;
  29. @Autowired
  30. public BuildManager(CommitDAO commitDAO, RecordDAO recordDAO, ResultDAO resultDAO, JenkinsApi jenkinsApi, ApplicationProperties properties) {
  31. this.commitDAO = commitDAO;
  32. this.recordDAO = recordDAO;
  33. this.resultDAO = resultDAO;
  34. this.jenkinsApi = jenkinsApi;
  35. this.properties = properties;
  36. }
  37. @SuppressWarnings("BooleanMethodIsAlwaysInverted")
  38. @Transactional
  39. public boolean invokeNextBuild(int resultId) {
  40. Result result = resultDAO.findById(resultId);
  41. if (result == null) return false;
  42. Record record;
  43. while ((record = nextUnbuiltRecord(result)) != null) {
  44. try {
  45. QueueItem item = jenkinsApi.invokeBuild(resultId, buildParam(record));
  46. record.setNumber(item.getExecutable().getNumber().intValue());
  47. record.setStatus(BuildStatus.RUNNING);
  48. return true;
  49. } catch (Exception e) {
  50. log.error("触发构建" + record.getId() + "时发生异常" + ToolKit.format(e));
  51. record.setConsoleOutput("系统内部发生未知异常,请尝试重新提交!");
  52. record.setStatus(BuildStatus.FAILURE);
  53. } finally {
  54. try {
  55. recordDAO.save(record);
  56. } catch (Exception saveException) {
  57. log.error("触发构建保存" + record.getId() + "时发生异常" + ToolKit.format(saveException));
  58. record.setConsoleOutput("系统内部发生未知异常,请尝试重新提交!");
  59. record.setStatus(BuildStatus.FAILURE);
  60. }
  61. }
  62. }
  63. return false;
  64. }
  65. @Transactional
  66. public boolean recordBuildResult(int id, int buildNumber) {
  67. Record record = recordDAO.findByResultIdAndBuildNumber(id, buildNumber);
  68. if (record == null || record.getStatus() != BuildStatus.RUNNING) {
  69. return false;
  70. }
  71. Problem problem = record.getProblem();
  72. ProblemType type = problem.getType();
  73. try {
  74. BuildDetails buildDetails = jenkinsApi.fetchBuildDetails(id, buildNumber, type.getTarget(), true);
  75. Evaluator evaluator = type.getEvaluator();
  76. evaluator.evaluate(record, buildDetails);
  77. } catch (Exception e) {
  78. log.error("获取构建记录" + buildNumber + "时发生异常" + ToolKit.format(e));
  79. record.setConsoleOutput("系统内部发生未知异常,请尝试重新提交!");
  80. record.setStatus(BuildStatus.FAILURE);
  81. } finally {
  82. try {
  83. recordDAO.save(record);
  84. } catch (Exception saveException) {
  85. log.error("构建保存" + record.getId() + "时发生异常" + ToolKit.format(saveException));
  86. record.setConsoleOutput(record.getConsoleOutput().substring(0, Math.min(record.getConsoleOutput().length(), 1024 * 1024 * 10)));
  87. record.setStatus(record.getStatus());
  88. recordDAO.save(record);
  89. }
  90. }
  91. return true;
  92. }
  93. private Record nextUnbuiltRecord(Result result) {
  94. Commit commit = commitDAO.findFirstUnfinishedByResult(result);
  95. if (commit == null) return null;
  96. Record unbuiltRecord = null;
  97. for (Record record : commit.getRecords()) {
  98. switch (record.getStatus()) {
  99. case RUNNING:
  100. return null;
  101. case WAITING:
  102. if (unbuiltRecord == null) {
  103. unbuiltRecord = record;
  104. }
  105. }
  106. }
  107. return unbuiltRecord;
  108. }
  109. private Map<String, String> buildParam(Record record) {
  110. Exam exam = record.getCommit().getResult().getExam();
  111. User user = record.getCommit().getResult().getOwner();
  112. Problem problem = record.getProblem();
  113. String uniqueName = problem.getUniqueName();
  114. ProblemHelper helper = problem.getType().getHelper();
  115. Map<String, String> param = new HashMap<>();
  116. param.put("PROB_TARGET", problem.getType().getTarget());
  117. param.put("GIT_URL", properties.getGitlab().getHost() + "/" + user.getUsername() + "/" + exam.getUuid());
  118. param.put("COMMIT_HASH", record.getCommit().getHash());
  119. param.put("DOCKER_IMAGE", properties.getDocker().getRegistry() + "/" + problem.getImageName() + ":" + problem.getImageTag());
  120. param.put("EXECUTE_SHELL", "#!/bin/bash\n"
  121. + "cp -R /var/ws/code/" + uniqueName + "/* /var/ws/tmp/ &>/dev/null || :\n"
  122. + "pushd " + uniqueName + " &>/dev/null\n"
  123. + "cp --parents -R ." + helper.editableDirectory() + "/*" + " /var/ws/tmp/ &>/dev/null || :\n"
  124. + "popd &>/dev/null\n"
  125. + helper.runScript(uniqueName));
  126. return param;
  127. }
  128. }