Beispiel #1
0
  /**
   * List of users who committed a change since the last non-broken build till now.
   *
   * <p>This list at least always include people who made changes in this build, but if the previous
   * build was a failure it also includes the culprit list from there. Culprits of unstable build
   * are also included see <a href="http://issues.hudson-ci.org/browse/HUDSON-4617">HUDSON-4617</a>
   * for details
   *
   * @return can be empty but never null.
   */
  @Exported
  public Set<User> getCulprits() {
    if (culprits == null) {
      Set<User> r = new HashSet<User>();
      R p = getPreviousCompletedBuild();
      if (p != null && isBuilding()) {
        Result pr = p.getResult();
        if (pr != null && pr.isWorseOrEqualTo(Result.UNSTABLE)) {
          // we are still building, so this is just the current latest information,
          // but we seems to be failing so far, so inherit culprits from the previous build.
          // isBuilding() check is to avoid recursion when loading data from old Hudson, which
          // doesn't record
          // this information
          r.addAll(p.getCulprits());
        }
      }
      for (Entry e : getChangeSet()) r.add(e.getAuthor());

      if (upstreamCulprits) {
        // If we have dependencies since the last successful build, add their authors to our list
        R previousBuild = getPreviousSuccessfulBuild();
        if (previousBuild != null) {
          Map<AbstractProject, AbstractBuild.DependencyChange> depmap =
              getDependencyChanges(previousBuild);
          for (AbstractBuild.DependencyChange dep : depmap.values()) {
            for (AbstractBuild<?, ?> b : dep.getBuilds()) {
              for (Entry entry : b.getChangeSet()) {
                r.add(entry.getAuthor());
              }
            }
          }
        }
      }

      return r;
    }

    return new AbstractSet<User>() {
      public Iterator<User> iterator() {
        return new AdaptedIterator<String, User>(culprits.iterator()) {
          protected User adapt(String id) {
            return User.get(id);
          }
        };
      }

      public int size() {
        return culprits.size();
      }
    };
  }
 @DataBoundConstructor
 public SelfHealingMatrixExecutionStrategy(
     String logPattern,
     Result worseThanOrEqualTo,
     Result betterThanOrEqualTo,
     int maxRetries,
     boolean stopRetryingAfterOneFails) {
   this.logPattern = logPattern == null ? "" : logPattern;
   this.worseThanOrEqualTo = worseThanOrEqualTo == null ? Result.FAILURE : worseThanOrEqualTo;
   this.betterThanOrEqualTo =
       betterThanOrEqualTo == null
           ? Result.ABORTED
           : betterThanOrEqualTo.isWorseOrEqualTo(this.worseThanOrEqualTo)
               ? betterThanOrEqualTo
               : this.worseThanOrEqualTo;
   this.maxRetries = maxRetries < 0 ? 1 : maxRetries;
   this.stopRetryingAfterOneFails = stopRetryingAfterOneFails;
 }
  /**
   * Waits for the given configurations to finish, retrying any that qualify to be rerun.
   *
   * @param execution Provided by the plugin.
   * @param patterns List of regular expression patterns used to scan the log to determine if a
   *     build should be rerun.
   * @param retries Mutable map that tracks the number of times a specific configuration has been
   *     retried.
   * @param configurations The configurations that have already been scheduled to run that should be
   *     waited for to finish.
   * @return The worst result of all the runs. If a build was rerun, only the result of the rerun is
   *     considered.
   * @throws InterruptedException
   * @throws IOException
   */
  private Result waitForMatrixRuns(
      MatrixBuild.MatrixBuildExecution execution,
      List<Pattern> patterns,
      Map<MatrixConfiguration, Integer> retries,
      LinkedList<MatrixConfiguration> configurations)
      throws InterruptedException, IOException {
    BuildListener listener = execution.getListener();
    PrintStream logger = listener.getLogger();

    Map<String, String> whyBlockedMap =
        new HashMap<
            String,
            String>(); // keep track of why builds are blocked so we can print unique messages when
    // they change.
    Result finalResult = Result.SUCCESS;
    int iteration = 0;
    boolean continueRetrying = true;
    while (!configurations.isEmpty()) {
      ++iteration;
      MatrixConfiguration configuration = configurations.removeFirst();
      if (isBuilding(execution, configuration, whyBlockedMap)) {
        if (iteration >= configurations.size()) {
          // Every time we loop through all the configurations, sleep for a bit.
          // This is to prevent polling too often while everything is still building.
          iteration = 0;
          Thread.sleep(1000);
        }
        configurations.add(configuration);
        continue;
      }

      Run parentBuild = execution.getBuild();
      MatrixRun matrixRun = configuration.getBuildByNumber(parentBuild.getNumber());
      Result runResult = matrixRun.getResult();
      if (continueRetrying
          && runResult.isWorseOrEqualTo(getWorseThanOrEqualTo())
          && runResult.isBetterOrEqualTo(getBetterThanOrEqualTo())) {
        if (matchesPattern(matrixRun, patterns)) {
          int retriedCount = retries.get(configuration);
          if (retriedCount < getMaxRetries()) {
            ++retriedCount;
            retries.put(configuration, retriedCount);
            // rerun
            String logMessage =
                String.format(
                    "%s was %s. Matched pattern to rerun. Rerunning (%d).",
                    matrixRun, runResult, retriedCount);
            listener.error(logMessage);

            HealedAction action = parentBuild.getAction(HealedAction.class);
            if (action == null) {
              //noinspection SynchronizationOnLocalVariableOrMethodParameter
              synchronized (parentBuild.getActions()) {
                action = parentBuild.getAction(HealedAction.class);
                if (action == null) {
                  action = new HealedAction(matrixRun.getCharset());
                  parentBuild.addAction(action);
                }
              }
            }
            action.addAutoHealedJob(matrixRun);

            MatrixConfiguration parent = matrixRun.getParent();
            if (parent != null) {
              // I'm paranoid about NPEs
              parent.removeRun(matrixRun);
              matrixRun.delete();
            } else {
              LOGGER.severe(
                  "couldn't remove old run, parent was null. This is a Jenkins core bug.");
            }
            scheduleConfigurationBuild(
                execution, configuration, new SelfHealingCause(parentBuild, retriedCount));
            configurations.add(configuration);
            continue;
          } else {
            String logMessage =
                String.format(
                    "%s was %s. Matched pattern to rerun, but the max number of retries (%d) has been met.",
                    matrixRun, runResult, getMaxRetries());
            listener.error(logMessage);
            if (getStopRetryingAfterOneFails()) {
              listener.error("Not retrying any more builds.");
              continueRetrying = false;
            }
          }
        } else {
          String logMessage =
              String.format(
                  "%s was %s. It did not match the pattern to rerun. Accepting result.",
                  matrixRun, runResult);
          logger.println(logMessage);
        }
      }
      notifyEndRun(matrixRun, execution.getAggregators(), execution.getListener());
      finalResult = finalResult.combine(runResult);
    }
    return finalResult;
  }