PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/modules/test/jenkins-results-parser/src/main/java/com/liferay/jenkins/results/parser/AutoCloseUtil.java

http://github.com/liferay/liferay-portal
Java | 833 lines | 616 code | 201 blank | 16 comment | 109 complexity | f04a0324a74a90548fb673b75e1145bc MD5 | raw file
Possible License(s): LGPL-2.0
  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. package com.liferay.jenkins.results.parser;
  15. import java.io.IOException;
  16. import java.util.ArrayList;
  17. import java.util.Arrays;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import java.util.Properties;
  21. import java.util.regex.Matcher;
  22. import java.util.regex.Pattern;
  23. import org.apache.commons.lang.StringUtils;
  24. /**
  25. * @author Peter Yoo
  26. */
  27. public class AutoCloseUtil {
  28. public static boolean debug = false;
  29. public static void autoClose(PullRequest pullRequest, Build build)
  30. throws Exception {
  31. if (pullRequest.isAutoCloseCommentAvailable()) {
  32. return;
  33. }
  34. String gitHubReceiverUsername = pullRequest.getOwnerUsername();
  35. String gitHubSenderUsername = pullRequest.getSenderUsername();
  36. if ((gitHubReceiverUsername == null) ||
  37. (gitHubSenderUsername == null) ||
  38. !_autoCloseReceiverUsernames.contains(gitHubReceiverUsername) ||
  39. gitHubReceiverUsername.equals(gitHubSenderUsername)) {
  40. return;
  41. }
  42. pullRequest.close();
  43. StringBuilder sb = new StringBuilder();
  44. sb.append("<h1>The pull request tester is still running.</h1>");
  45. sb.append("<p>Please wait until you get the ");
  46. sb.append("<i><b>final report</b></i> before running 'ci:retest'.");
  47. sb.append("</p><p>See this link to check on the status of your ");
  48. sb.append("test:</p>");
  49. sb.append("<ul><li><a href=\"");
  50. sb.append(build.getBuildURL());
  51. sb.append("\">");
  52. sb.append(build.getJobName());
  53. sb.append("</a></li></ul><p>@");
  54. sb.append(pullRequest.getSenderUsername());
  55. sb.append("</p><hr />");
  56. sb.append("<h1>However, the pull request was closed.</h1>");
  57. sb.append("<p>The pull request was closed because the following ");
  58. sb.append("critical builds had failed:</p><ul>");
  59. sb.append("<li><a href=\"");
  60. sb.append(build.getBuildURL());
  61. sb.append("\">");
  62. String jobVariant = build.getJobVariant();
  63. if ((jobVariant != null) && !jobVariant.isEmpty()) {
  64. sb.append(jobVariant);
  65. }
  66. else {
  67. sb.append(build.getJobName());
  68. }
  69. sb.append("</a></li></ul><p>For information as to why we ");
  70. sb.append("automatically close out certain pull requests see this ");
  71. sb.append("<a href=\"https://in.liferay.com/web/global.");
  72. sb.append("engineering/wiki/-/wiki/Quality+Assurance+Main/Test");
  73. sb.append("+Batch+Automatic+Close+List\">article</a>.</p><p");
  74. boolean sourceFormatBuild = build instanceof SourceFormatBuild;
  75. if (sourceFormatBuild) {
  76. sb.append("><strong><em>*");
  77. }
  78. else {
  79. sb.append(" auto-close=\"false\"><strong><em>*This pull will ");
  80. sb.append("no longer automatically close if this comment is ");
  81. sb.append("available. ");
  82. }
  83. sb.append("If you believe this is a mistake please reopen this ");
  84. sb.append("pull by entering the following command as a comment.");
  85. sb.append("</em></strong><pre>ci&#58;reopen</pre></p>");
  86. if (sourceFormatBuild) {
  87. sb.append("<strong><em>*The reopened pull request may ");
  88. sb.append("be automatically closed again if other critical ");
  89. sb.append("batches or tests fail.</em></strong>");
  90. }
  91. sb.append("<hr /><h3>Critical Failure Details:</h3>");
  92. try {
  93. sb.append(Dom4JUtil.format(build.getGitHubMessageElement(), false));
  94. }
  95. catch (Exception exception) {
  96. exception.printStackTrace();
  97. throw exception;
  98. }
  99. if (!_autoCloseGitHubCommentMentionUsernames.isEmpty()) {
  100. sb.append("<div>cc");
  101. for (String autoCloseGitHubCommentMentionUsername :
  102. _autoCloseGitHubCommentMentionUsernames) {
  103. sb.append(" @");
  104. sb.append(autoCloseGitHubCommentMentionUsername);
  105. }
  106. sb.append("</div>");
  107. }
  108. pullRequest.addComment(sb.toString());
  109. }
  110. public static boolean autoCloseOnCriticalBatchFailures(
  111. PullRequest pullRequest, Build topLevelBuild)
  112. throws Exception {
  113. if (pullRequest.isAutoCloseCommentAvailable()) {
  114. return false;
  115. }
  116. String gitHubReceiverUsername = pullRequest.getOwnerUsername();
  117. String gitHubSenderUsername = pullRequest.getSenderUsername();
  118. if ((gitHubReceiverUsername == null) ||
  119. (gitHubSenderUsername == null) ||
  120. !_autoCloseReceiverUsernames.contains(gitHubReceiverUsername) ||
  121. gitHubReceiverUsername.equals(gitHubSenderUsername)) {
  122. return false;
  123. }
  124. List<AutoCloseRule> autoCloseRules = getAutoCloseRules(pullRequest);
  125. for (AutoCloseRule autoCloseRule : autoCloseRules) {
  126. List<Build> downstreamBuilds = topLevelBuild.getDownstreamBuilds(
  127. null);
  128. if (downstreamBuilds.isEmpty()) {
  129. downstreamBuilds = new ArrayList<>();
  130. downstreamBuilds.add(topLevelBuild);
  131. }
  132. List<Build> failedDownstreamBuilds = autoCloseRule.evaluate(
  133. downstreamBuilds);
  134. if (failedDownstreamBuilds.isEmpty()) {
  135. continue;
  136. }
  137. pullRequest.close();
  138. StringBuilder sb = new StringBuilder();
  139. sb.append("<h1>The pull request tester is still running.</h1>");
  140. sb.append("<p>Please wait until you get the ");
  141. sb.append("<i><b>final report</b></i> before running 'ci:retest'.");
  142. sb.append("</p><p>See this link to check on the status of your ");
  143. sb.append("test:</p>");
  144. sb.append("<ul><li><a href=\"");
  145. sb.append(topLevelBuild.getBuildURL());
  146. sb.append("\">");
  147. sb.append(topLevelBuild.getJobName());
  148. sb.append("</a></li></ul><p>@");
  149. sb.append(gitHubSenderUsername);
  150. sb.append("</p><hr />");
  151. sb.append("<h1>However, the pull request was closed.</h1>");
  152. sb.append("<p>The pull request was closed because the following ");
  153. sb.append("critical batches had failed:</p><ul>");
  154. String failureBuildURL = "";
  155. for (Build failedDownstreamBuild : failedDownstreamBuilds) {
  156. failureBuildURL = failedDownstreamBuild.getBuildURL();
  157. sb.append("<li><a href=\"");
  158. sb.append(failureBuildURL);
  159. sb.append("\">");
  160. String jobVariant = failedDownstreamBuild.getJobVariant();
  161. if ((jobVariant != null) && !jobVariant.isEmpty()) {
  162. sb.append(jobVariant);
  163. }
  164. else {
  165. sb.append(failedDownstreamBuild.getJobName());
  166. }
  167. sb.append("</a></li>");
  168. }
  169. sb.append("</ul><p>For information as to why we automatically ");
  170. sb.append("close out certain pull requests see this ");
  171. sb.append("<a href=\"https://in.liferay.com/web/global.");
  172. sb.append("engineering/wiki/-/wiki/Quality+Assurance+Main/Test");
  173. sb.append("+Batch+Automatic+Close+List\">article</a>.</p><p");
  174. boolean sourceFormatBuild =
  175. topLevelBuild instanceof SourceFormatBuild;
  176. if (sourceFormatBuild) {
  177. sb.append("><strong><em>*");
  178. }
  179. else {
  180. sb.append(" auto-close=\"false\"><strong><em>*This pull will ");
  181. sb.append("no longer automatically close if this comment is ");
  182. sb.append("available. ");
  183. }
  184. sb.append("If you believe this is a mistake please reopen this ");
  185. sb.append("pull by entering the following command as a comment.");
  186. sb.append("</em></strong><pre>ci&#58;reopen</pre></p>");
  187. if (sourceFormatBuild) {
  188. sb.append("<strong><em>*The reopened pull request may ");
  189. sb.append("be automatically closed again if other critical ");
  190. sb.append("batches or tests fail.</em></strong>");
  191. }
  192. sb.append("<hr /><h3>Critical Failure Details:</h3>");
  193. for (Build failedDownstreamBuild : failedDownstreamBuilds) {
  194. try {
  195. sb.append(
  196. Dom4JUtil.format(
  197. failedDownstreamBuild.getGitHubMessageElement(),
  198. false));
  199. }
  200. catch (Exception exception) {
  201. exception.printStackTrace();
  202. throw exception;
  203. }
  204. }
  205. if (!_autoCloseGitHubCommentMentionUsernames.isEmpty()) {
  206. sb.append("<div>cc");
  207. for (String autoCloseGitHubCommentMentionUsername :
  208. _autoCloseGitHubCommentMentionUsernames) {
  209. sb.append(" @");
  210. sb.append(autoCloseGitHubCommentMentionUsername);
  211. }
  212. sb.append("</div>");
  213. }
  214. pullRequest.addComment(sb.toString());
  215. return true;
  216. }
  217. return false;
  218. }
  219. public static boolean autoCloseOnCriticalTestFailures(
  220. PullRequest pullRequest, Build topLevelBuild)
  221. throws Exception {
  222. if (pullRequest.isAutoCloseCommentAvailable() ||
  223. !isAutoCloseOnCriticalTestFailuresActive(pullRequest)) {
  224. return false;
  225. }
  226. String gitHubReceiverUsername = pullRequest.getOwnerUsername();
  227. String gitHubSenderUsername = pullRequest.getSenderUsername();
  228. if ((gitHubReceiverUsername == null) ||
  229. (gitHubSenderUsername == null) ||
  230. !_autoCloseReceiverUsernames.contains(gitHubReceiverUsername) ||
  231. gitHubReceiverUsername.equals(gitHubSenderUsername)) {
  232. return false;
  233. }
  234. Build failedDownstreamBuild = null;
  235. List<String> jenkinsJobFailureURLs = new ArrayList<>();
  236. List<Build> downstreamBuilds = topLevelBuild.getDownstreamBuilds(null);
  237. Properties localLiferayJenkinsEEBuildProperties =
  238. JenkinsResultsParserUtil.getLocalLiferayJenkinsEEBuildProperties();
  239. for (Build downstreamBuild : downstreamBuilds) {
  240. String batchName = downstreamBuild.getJobVariant();
  241. if (batchName == null) {
  242. continue;
  243. }
  244. if (!batchName.contains("integration") &&
  245. !batchName.contains("unit")) {
  246. continue;
  247. }
  248. String status = downstreamBuild.getStatus();
  249. if (!status.equals("completed")) {
  250. continue;
  251. }
  252. String result = downstreamBuild.getResult();
  253. if ((result == null) || !result.equals("UNSTABLE")) {
  254. continue;
  255. }
  256. String gitSubrepositoryPackageNames =
  257. JenkinsResultsParserUtil.getProperty(
  258. localLiferayJenkinsEEBuildProperties,
  259. "subrepository.package.names");
  260. if (gitSubrepositoryPackageNames == null) {
  261. continue;
  262. }
  263. for (String gitSubrepositoryPackageName :
  264. gitSubrepositoryPackageNames.split(",")) {
  265. if (!jenkinsJobFailureURLs.isEmpty()) {
  266. break;
  267. }
  268. List<TestResult> testResults = new ArrayList<>();
  269. testResults.addAll(downstreamBuild.getTestResults("FAILED"));
  270. testResults.addAll(
  271. downstreamBuild.getTestResults("REGRESSION"));
  272. for (TestResult testResult : testResults) {
  273. if (UpstreamFailureUtil.isTestFailingInUpstreamJob(
  274. testResult)) {
  275. continue;
  276. }
  277. if (gitSubrepositoryPackageName.equals(
  278. testResult.getPackageName())) {
  279. failedDownstreamBuild = downstreamBuild;
  280. StringBuilder sb = new StringBuilder();
  281. sb.append("<a href=\"");
  282. sb.append(testResult.getTestReportURL());
  283. sb.append("\">");
  284. sb.append(testResult.getClassName());
  285. sb.append("</a>");
  286. jenkinsJobFailureURLs.add(sb.toString());
  287. }
  288. }
  289. }
  290. }
  291. if (!jenkinsJobFailureURLs.isEmpty()) {
  292. pullRequest.close();
  293. StringBuilder sb = new StringBuilder();
  294. sb.append("<h1>The pull request tester is still running.</h1>");
  295. sb.append("<p>Please wait until you get the <i><b>final report");
  296. sb.append("</b></i> before running 'ci:retest'.</p><p>See this ");
  297. sb.append("link to check on the status of your test:</p>");
  298. sb.append("<ul><li><a href=\"");
  299. sb.append(topLevelBuild.getBuildURL());
  300. sb.append("\">");
  301. sb.append(topLevelBuild.getJobName());
  302. sb.append("</a></li></ul>@");
  303. sb.append(gitHubSenderUsername);
  304. sb.append("</p><hr />");
  305. sb.append("<h1>However, the pull request was closed.</h1>");
  306. sb.append("<p>The pull request was closed due to the following ");
  307. sb.append("integration/unit test failures:</p><ul>");
  308. for (String jenkinsJobFailureURL : jenkinsJobFailureURLs) {
  309. sb.append("<li>");
  310. sb.append(jenkinsJobFailureURL);
  311. sb.append("</li>");
  312. }
  313. sb.append("</ul><p>These test failures are a part of a ");
  314. sb.append("'module group'/'subrepository' that was changed in ");
  315. sb.append("this pull request.</p>");
  316. sb.append("<p auto-close=\"false\"><strong><em>*This pull will ");
  317. sb.append("no longer automatically close if this comment is ");
  318. sb.append("available. If you believe this is a mistake please ");
  319. sb.append("reopen this pull by entering the following command ");
  320. sb.append("as a comment.</em></strong></p><pre>ci&#58;reopen");
  321. sb.append("</pre><hr /><h3>Critical Failure Details:</h3>");
  322. try {
  323. sb.append(
  324. Dom4JUtil.format(
  325. failedDownstreamBuild.getGitHubMessageElement(),
  326. false));
  327. }
  328. catch (Exception exception) {
  329. exception.printStackTrace();
  330. throw exception;
  331. }
  332. if (!_autoCloseGitHubCommentMentionUsernames.isEmpty()) {
  333. sb.append("<div>cc");
  334. for (String autoCloseGithubCommentMentionUsername :
  335. _autoCloseGitHubCommentMentionUsernames) {
  336. sb.append(" @");
  337. sb.append(autoCloseGithubCommentMentionUsername);
  338. }
  339. sb.append("</div>");
  340. }
  341. pullRequest.addComment(sb.toString());
  342. return true;
  343. }
  344. return false;
  345. }
  346. public static List<AutoCloseRule> getAutoCloseRules(PullRequest pullRequest)
  347. throws Exception {
  348. List<AutoCloseRule> list = new ArrayList<>();
  349. String propertyNameTemplate = JenkinsResultsParserUtil.combine(
  350. "test.batch.names.auto.close[",
  351. pullRequest.getGitHubRemoteGitRepositoryName(), "?]");
  352. String gitRepositoryBranchAutoClosePropertyName =
  353. propertyNameTemplate.replace(
  354. "?", "-" + pullRequest.getUpstreamBranchName());
  355. Properties localLiferayJenkinsEEBuildProperties =
  356. JenkinsResultsParserUtil.getLocalLiferayJenkinsEEBuildProperties();
  357. String testBatchNamesAutoClose = JenkinsResultsParserUtil.getProperty(
  358. localLiferayJenkinsEEBuildProperties,
  359. gitRepositoryBranchAutoClosePropertyName);
  360. if (testBatchNamesAutoClose == null) {
  361. String gitRepositoryAutoClosePropertyName =
  362. propertyNameTemplate.replace("?", "");
  363. testBatchNamesAutoClose = JenkinsResultsParserUtil.getProperty(
  364. localLiferayJenkinsEEBuildProperties,
  365. gitRepositoryAutoClosePropertyName);
  366. }
  367. if (testBatchNamesAutoClose != null) {
  368. if (debug) {
  369. System.out.println(
  370. JenkinsResultsParserUtil.combine(
  371. "Finding auto-close rules for ",
  372. gitRepositoryBranchAutoClosePropertyName, "."));
  373. }
  374. String[] autoCloseRuleDataArray = StringUtils.split(
  375. testBatchNamesAutoClose, ",");
  376. for (String autoCloseRuleData : autoCloseRuleDataArray) {
  377. if (autoCloseRuleData.startsWith("#")) {
  378. continue;
  379. }
  380. if (autoCloseRuleData.startsWith("static_")) {
  381. continue;
  382. }
  383. AutoCloseRule newAutoCloseRule = new AutoCloseRule(
  384. autoCloseRuleData);
  385. if (debug) {
  386. System.out.println("\t" + newAutoCloseRule.toString());
  387. }
  388. list.add(newAutoCloseRule);
  389. }
  390. if (debug) {
  391. System.out.println(
  392. JenkinsResultsParserUtil.combine(
  393. "Finished finding ",
  394. gitRepositoryBranchAutoClosePropertyName,
  395. " auto-close rules.\n"));
  396. }
  397. }
  398. return list;
  399. }
  400. public static boolean isAutoCloseBranch(PullRequest pullRequest) {
  401. String gitHubRemoteGitRepositoryName =
  402. pullRequest.getGitHubRemoteGitRepositoryName();
  403. String testBranchNamesAutoClose = JenkinsResultsParserUtil.getProperty(
  404. JenkinsResultsParserUtil.getLocalLiferayJenkinsEEBuildProperties(),
  405. JenkinsResultsParserUtil.combine(
  406. "test.branch.names.auto.close[", gitHubRemoteGitRepositoryName,
  407. "]"));
  408. String branchName = pullRequest.getUpstreamBranchName();
  409. if (testBranchNamesAutoClose == null) {
  410. if (debug) {
  411. System.out.println(
  412. JenkinsResultsParserUtil.combine(
  413. "Auto-close rules are deactivated for ",
  414. gitHubRemoteGitRepositoryName, "(", branchName, ")."));
  415. }
  416. return false;
  417. }
  418. List<String> testBranchNamesAutoCloseList = Arrays.asList(
  419. testBranchNamesAutoClose.split(","));
  420. return testBranchNamesAutoCloseList.contains(branchName);
  421. }
  422. public static boolean isAutoCloseOnCriticalTestFailuresActive(
  423. PullRequest pullRequest) {
  424. String criticalTestBranchesString =
  425. JenkinsResultsParserUtil.getProperty(
  426. JenkinsResultsParserUtil.
  427. getLocalLiferayJenkinsEEBuildProperties(),
  428. JenkinsResultsParserUtil.combine(
  429. "test.branch.names.critical.test[",
  430. pullRequest.getGitHubRemoteGitRepositoryName(), "]"));
  431. if ((criticalTestBranchesString == null) ||
  432. criticalTestBranchesString.isEmpty()) {
  433. return false;
  434. }
  435. String[] criticalTestBranches = StringUtils.split(
  436. criticalTestBranchesString, ",");
  437. for (String criticalTestBranch : criticalTestBranches) {
  438. if (criticalTestBranch.equals(
  439. pullRequest.getUpstreamBranchName())) {
  440. return true;
  441. }
  442. }
  443. return false;
  444. }
  445. private static List<String> _getBuildPropertyAsList(String propertyName) {
  446. try {
  447. return JenkinsResultsParserUtil.getBuildPropertyAsList(
  448. true, propertyName);
  449. }
  450. catch (IOException ioException) {
  451. throw new RuntimeException(
  452. "Unable to get property " + propertyName, ioException);
  453. }
  454. }
  455. private static final List<String> _autoCloseGitHubCommentMentionUsernames =
  456. _getBuildPropertyAsList("auto.close.github.comment.mention.usernames");
  457. private static final List<String> _autoCloseReceiverUsernames =
  458. _getBuildPropertyAsList("auto.close.receiver.usernames");
  459. private static class AutoCloseRule {
  460. public AutoCloseRule(String ruleData) {
  461. this.ruleData = ruleData;
  462. String[] ruleDataArray = ruleData.split("\\|");
  463. rulePattern = Pattern.compile(ruleDataArray[0]);
  464. if (ruleDataArray[1].endsWith("%")) {
  465. String percentageRule = ruleDataArray[1];
  466. int i = Integer.parseInt(
  467. percentageRule.substring(0, percentageRule.length() - 1));
  468. maxFailPercentage = i / 100;
  469. }
  470. else {
  471. maxFailCount = Integer.parseInt(ruleDataArray[1]);
  472. }
  473. }
  474. public List<Build> evaluate(List<Build> downstreamBuilds) {
  475. if (debug) {
  476. System.out.println(
  477. JenkinsResultsParserUtil.combine(
  478. "Evaluating auto-close rule ", toString(), "."));
  479. }
  480. try {
  481. downstreamBuilds = getMatchingBuilds(downstreamBuilds);
  482. if (debug) {
  483. System.out.println(
  484. JenkinsResultsParserUtil.combine(
  485. "Found ", String.valueOf(downstreamBuilds.size()),
  486. " builds that match this rule."));
  487. }
  488. List<Build> failingInUpstreamJobDownstreamBuilds =
  489. new ArrayList<>(downstreamBuilds.size());
  490. for (Build downstreamBuild : downstreamBuilds) {
  491. if (UpstreamFailureUtil.isBuildFailingInUpstreamJob(
  492. downstreamBuild)) {
  493. failingInUpstreamJobDownstreamBuilds.add(
  494. downstreamBuild);
  495. continue;
  496. }
  497. List<TestResult> testResults = new ArrayList<>();
  498. testResults.addAll(
  499. downstreamBuild.getTestResults("FAILED"));
  500. testResults.addAll(
  501. downstreamBuild.getTestResults("REGRESSION"));
  502. boolean containsUniqueTestFailure = false;
  503. if (testResults.isEmpty()) {
  504. containsUniqueTestFailure = true;
  505. }
  506. else {
  507. for (TestResult testResult : testResults) {
  508. if (!UpstreamFailureUtil.isTestFailingInUpstreamJob(
  509. testResult)) {
  510. containsUniqueTestFailure = true;
  511. break;
  512. }
  513. }
  514. }
  515. if (!containsUniqueTestFailure) {
  516. failingInUpstreamJobDownstreamBuilds.add(
  517. downstreamBuild);
  518. }
  519. }
  520. if (debug) {
  521. System.out.println(
  522. JenkinsResultsParserUtil.combine(
  523. String.valueOf(
  524. failingInUpstreamJobDownstreamBuilds.size()),
  525. " downstream builds are also failing in ",
  526. "upstream."));
  527. }
  528. downstreamBuilds.removeAll(
  529. failingInUpstreamJobDownstreamBuilds);
  530. if (downstreamBuilds.isEmpty()) {
  531. if (debug) {
  532. System.out.println(toString() + " has PASSED.");
  533. }
  534. return Collections.emptyList();
  535. }
  536. List<Build> failedDownstreamBuilds = new ArrayList<>(
  537. downstreamBuilds.size());
  538. int failLimit = 0;
  539. if (maxFailPercentage != -1) {
  540. failLimit =
  541. (int)(maxFailPercentage * downstreamBuilds.size());
  542. if (failLimit > 0) {
  543. failLimit--;
  544. }
  545. }
  546. else {
  547. failLimit = maxFailCount;
  548. }
  549. if (debug) {
  550. System.out.println(
  551. JenkinsResultsParserUtil.combine(
  552. toString(), " fail limit is ",
  553. String.valueOf(failLimit)));
  554. }
  555. for (Build downstreamBuild : downstreamBuilds) {
  556. String status = downstreamBuild.getStatus();
  557. if (!status.equals("completed")) {
  558. continue;
  559. }
  560. String result = downstreamBuild.getResult();
  561. if ((result != null) && !result.equals("SUCCESS")) {
  562. if (debug) {
  563. System.out.println(
  564. JenkinsResultsParserUtil.combine(
  565. "Found a matching failed build. ",
  566. downstreamBuild.getDisplayName(),
  567. " has failed."));
  568. }
  569. failedDownstreamBuilds.add(downstreamBuild);
  570. }
  571. }
  572. if (failedDownstreamBuilds.size() > failLimit) {
  573. if (debug) {
  574. System.out.println(
  575. JenkinsResultsParserUtil.combine(
  576. "Found ",
  577. String.valueOf(failedDownstreamBuilds.size()),
  578. " matching failed builds.\n", toString(),
  579. " has FAILED."));
  580. }
  581. return failedDownstreamBuilds;
  582. }
  583. if (debug) {
  584. System.out.println(
  585. JenkinsResultsParserUtil.combine(
  586. "Found ",
  587. String.valueOf(failedDownstreamBuilds.size()),
  588. " matching failed builds.\n", toString(),
  589. " has PASSED."));
  590. }
  591. return Collections.emptyList();
  592. }
  593. finally {
  594. if (debug) {
  595. System.out.println(
  596. JenkinsResultsParserUtil.combine(
  597. "Finished evaluating rule ", toString(), "\n"));
  598. }
  599. }
  600. }
  601. @Override
  602. public String toString() {
  603. return ruleData;
  604. }
  605. protected List<Build> getMatchingBuilds(List<Build> downstreamBuilds) {
  606. List<Build> filteredDownstreamBuilds = new ArrayList<>(
  607. downstreamBuilds.size());
  608. for (Build downstreamBuild : downstreamBuilds) {
  609. String jobVariant = downstreamBuild.getJobVariant();
  610. if ((jobVariant != null) && !jobVariant.isEmpty()) {
  611. Matcher matcher = rulePattern.matcher(jobVariant);
  612. if (matcher.matches()) {
  613. filteredDownstreamBuilds.add(downstreamBuild);
  614. continue;
  615. }
  616. }
  617. String jobName = downstreamBuild.getJobName();
  618. if ((jobName != null) && !jobName.isEmpty()) {
  619. Matcher matcher = rulePattern.matcher(jobName);
  620. if (matcher.matches()) {
  621. filteredDownstreamBuilds.add(downstreamBuild);
  622. }
  623. }
  624. }
  625. return filteredDownstreamBuilds;
  626. }
  627. protected int maxFailCount = -1;
  628. protected float maxFailPercentage = -1;
  629. protected String ruleData;
  630. protected Pattern rulePattern;
  631. }
  632. }