@Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException, IOException {

    Result result = build.getResult();
    if (result == null) {
      result = Result.SUCCESS;
    }

    String packIdString = getPackageId(build, listener);
    PackId packId = PackId.parsePid(packIdString);
    if (packId == null) {
      listener.fatalError("Failed to parse Package ID: %s%n", packIdString);
      return false;
    }

    String wspFilterString = getWspFilter(build, listener);
    WspFilter filter = WspFilter.parseSimpleSpec(wspFilterString);

    GraniteClientConfig clientConfig =
        new GraniteClientConfig(
            getBaseUrl(build, listener), credentialsId, requestTimeout, serviceTimeout, waitDelay);

    BuildPackageCallable callable =
        new BuildPackageCallable(clientConfig, listener, packId, filter, download);

    final String fLocalDirectory = getLocalDirectory(build, listener);
    result = result.combine(build.getWorkspace().child(fLocalDirectory).act(callable));

    return result.isBetterOrEqualTo(Result.UNSTABLE);
  }
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException, IOException {
    ArgumentListBuilder args = new ArgumentListBuilder();

    VariableResolver<String> vr = build.getBuildVariableResolver();

    String execName = NantInstallation.getExecutableName();

    // Get the path to the nant installation
    NantInstallation ni = getNant();
    if (ni == null) {
      args.add(
          launcher.isUnix()
              ? NantConstants.NANT_EXECUTABLE_UNIX
              : NantConstants.NANT_EXECUTABLE_WINDOWS);
    } else {
      args.add(ni.getExecutable(launcher));
    }

    // If a nant build file is specified, then add it as an argument, otherwise
    // nant will search for any file that ends in .build
    if (nantBuildFile != null && nantBuildFile.trim().length() > 0) {
      args.add("-buildfile:" + nantBuildFile);
    }

    // add the property declarations to the command line
    args.addKeyValuePairsFromPropertyString("-D:", properties, vr);

    // Remove all tabs, carriage returns, and newlines and replace them with
    // spaces, so that we can add them as parameters to the executable
    String normalizedTarget = targets.replaceAll("[\t\r\n]+", " ");
    if (normalizedTarget.trim().length() > 0) args.addTokenized(normalizedTarget);

    // According to the Ant builder source code, in order to launch a program
    // from the command line in windows, we must wrap it into cmd.exe.  This
    // way the return code can be used to determine whether or not the build failed.
    if (!launcher.isUnix()) {
      args = args.toWindowsCommand();
    }

    // Try to execute the command
    listener.getLogger().println("Executing command: " + args.toString());
    Map<String, String> env = build.getEnvironment(listener);
    try {
      int r =
          launcher.launch().cmds(args).envs(env).stdout(listener).pwd(build.getModuleRoot()).join();
      return r == 0;
    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("command execution failed"));
      return false;
    }
  }
  /**
   * Perform the sbt build. Interpret the command arguments and create a command line, then run it.
   */
  @Override
  public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) {

    EnvVars env = null;
    FilePath workDir = build.getModuleRoot();
    try {

      ArgumentListBuilder cmdLine = buildCmdLine(build, launcher, listener);
      String[] cmds = cmdLine.toCommandArray();
      env = build.getEnvironment(listener);

      if (subdirPath != null && subdirPath.length() > 0) {
        workDir = new FilePath(workDir, subdirPath);
      }

      int exitValue = launcher.launch().cmds(cmds).envs(env).stdout(listener).pwd(workDir).join();

      boolean success = (exitValue == 0);
      build.setResult(success ? Result.SUCCESS : Result.FAILURE);
      return success;
    } catch (IllegalArgumentException e) {
      // Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("command execution failed: " + e.getMessage()));
      build.setResult(Result.FAILURE);
      return false;
    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("command execution failed: " + e.getMessage()));
      build.setResult(Result.FAILURE);
      return false;
    } catch (InterruptedException e) {
      // Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("command execution failed: " + e.getMessage()));
      build.setResult(Result.ABORTED);
      return false;
    }
  }
  @Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException, IOException {
    EnvVars env = build.getEnvironment(listener);
    FilePath workDir = build.getModuleRoot();
    ArgumentListBuilder cmdLine = buildMavenCmdLine(build, listener, env);
    StringBuilder javaPathBuilder = new StringBuilder();

    JDK configuredJdk = build.getProject().getJDK();
    if (configuredJdk != null) {
      javaPathBuilder
          .append(build.getProject().getJDK().getBinDir().getCanonicalPath())
          .append(File.separator);
    }
    javaPathBuilder.append("java");
    if (!launcher.isUnix()) {
      javaPathBuilder.append(".exe");
    }
    String[] cmds = cmdLine.toCommandArray();
    try {
      // listener.getLogger().println("Executing: " + cmdLine.toStringWithQuote());
      int exitValue =
          launcher
              .launch()
              .cmds(new File(javaPathBuilder.toString()), cmds)
              .envs(env)
              .stdout(listener)
              .pwd(workDir)
              .join();
      boolean success = (exitValue == 0);
      build.setResult(success ? Result.SUCCESS : Result.FAILURE);
      return success;
    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("command execution failed"));
      build.setResult(Result.FAILURE);
      return false;
    }
  }
  /**
   * Changes the build result if baseline operation fails. (So cannot override {@linkplain
   * #needsToRunAfterFinalized()}).
   */
  @Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws IOException, InterruptedException {
    Logger.debug("Invoking perform callout " + this.getClass().getName());
    long key = -1L;
    try {
      if (!(build.getProject().getScm() instanceof DimensionsSCM)) {
        final String message =
            "[DIMENSIONS] This plugin only works with the Dimensions SCM engine.";
        listener.fatalError(message);
        build.setResult(Result.FAILURE);
        throw new IOException(message);
      }
      // Create baseline if SUCCESS or UNSTABLE (could be just some Checkstyle violations).
      Result result = build.getResult();
      if (result != null && result.isBetterThan(Result.FAILURE)) {
        if (scm == null) {
          scm = (DimensionsSCM) build.getProject().getScm();
        }
        Logger.debug(
            "Dimensions user is "
                + scm.getJobUserName()
                + " , Dimensions installation is "
                + scm.getJobServer());
        key =
            scm.getAPI()
                .login(
                    scm.getJobUserName(),
                    scm.getJobPasswd(),
                    scm.getJobDatabase(),
                    scm.getJobServer(),
                    build);
        if (key > 0L) {
          VariableResolver<String> myResolver = build.getBuildVariableResolver();
          String requests = myResolver.resolve("DM_TARGET_REQUEST");
          String blnId = myResolver.resolve("DM_BASELINE");
          StringBuffer cblId = new StringBuffer();

          if (requests != null) {
            requests = requests.replaceAll(" ", "");
            requests = requests.toUpperCase(Values.ROOT_LOCALE);
          }

          if (blnScope != null && blnScope.length() > 0 && blnScope.equals("REVISED")) {
            if (requests == null
                || blnId == null
                || requests.length() == 0
                || blnId.length() == 0) {
              listener.fatalError(
                  "[DIMENSIONS] A revised baseline is only valid if you have specified DM_TARGET_REQUEST and DM_BASELINE.");
              build.setResult(Result.FAILURE);
              return false;
            }
          }

          {
            DimensionsResult res =
                scm.getAPI()
                    .createBaseline(
                        key,
                        scm.getProjectVersion(build, listener),
                        build,
                        blnScope,
                        blnTemplate,
                        blnOwningPart,
                        blnType,
                        requests,
                        blnId,
                        blnName,
                        cblId);
            if (res == null) {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] The build failed to be tagged in Dimensions");
              listener.getLogger().flush();
              build.setResult(Result.FAILURE);
              canBaselineDeploy = canBaselineAction = canBaselineBuild = false;
            } else {
              listener
                  .getLogger()
                  .println(
                      "[DIMENSIONS] Build was successfully tagged in Dimensions as a baseline");
              listener
                  .getLogger()
                  .println(
                      "[DIMENSIONS] ("
                          + res.getMessage().replaceAll("\n", "\n[DIMENSIONS] ")
                          + ")");
              listener.getLogger().flush();
            }
          }
          if (canBaselineDeploy) {
            listener
                .getLogger()
                .println("[DIMENSIONS] Submitting a deployment job to Dimensions...");
            listener.getLogger().flush();
            DimensionsResult res =
                scm.getAPI()
                    .deployBaseline(
                        key,
                        scm.getProjectName(build, listener),
                        build,
                        deployState,
                        cblId.toString());
            if (res == null) {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] The build baseline failed to be deployed in Dimensions");
              listener.getLogger().flush();
              build.setResult(Result.FAILURE);
              canBaselineDeploy = canBaselineAction = canBaselineBuild = false;
            } else {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] Build baseline was successfully deployed in Dimensions");
              listener
                  .getLogger()
                  .println(
                      "[DIMENSIONS] ("
                          + res.getMessage().replaceAll("\n", "\n[DIMENSIONS] ")
                          + ")");
              listener.getLogger().flush();
            }
          }

          // This will active the build baseline functionality
          if (canBaselineBuild) {
            listener.getLogger().println("[DIMENSIONS] Submitting a build job to Dimensions...");
            listener.getLogger().flush();
            DimensionsResult res =
                scm.getAPI()
                    .buildBaseline(
                        key,
                        area,
                        scm.getProjectName(build, listener),
                        batch,
                        buildClean,
                        buildConfig,
                        buildOptions,
                        capture,
                        requests,
                        buildTargets,
                        build,
                        cblId.toString());
            if (res == null) {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] The build baseline failed to be built in Dimensions");
              listener.getLogger().flush();
              build.setResult(Result.FAILURE);
              canBaselineDeploy = canBaselineAction = canBaselineBuild = false;
            } else {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] Build baseline was successfully built in Dimensions");
              listener
                  .getLogger()
                  .println(
                      "[DIMENSIONS] ("
                          + res.getMessage().replaceAll("\n", "\n[DIMENSIONS] ")
                          + ")");
              listener.getLogger().flush();
            }
          }

          if (canBaselineAction) {
            listener
                .getLogger()
                .println("[DIMENSIONS] Actioning the build baseline in Dimensions...");
            listener.getLogger().flush();
            DimensionsResult res =
                scm.getAPI()
                    .actionBaseline(
                        key,
                        scm.getProjectName(build, listener),
                        build,
                        actionState,
                        cblId.toString());
            if (res == null) {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] The build baseline failed to be actioned in Dimensions");
              build.setResult(Result.FAILURE);
              listener.getLogger().flush();
            } else {
              listener
                  .getLogger()
                  .println("[DIMENSIONS] Build baseline was successfully actioned in Dimensions");
              listener
                  .getLogger()
                  .println(
                      "[DIMENSIONS] ("
                          + res.getMessage().replaceAll("\n", "\n[DIMENSIONS] ")
                          + ")");
              listener.getLogger().flush();
            }
          }
        } else {
          listener.fatalError("[DIMENSIONS] Login to Dimensions failed.");
          build.setResult(Result.FAILURE);
          return false;
        }
      }
    } catch (Exception e) {
      String message =
          Values.exceptionMessage("Unable to tag build in Dimensions", e, "no message");
      listener.fatalError(message);
      Logger.debug(message, e);
      build.setResult(Result.FAILURE);
      return false;
    } finally {
      if (scm != null) {
        scm.getAPI().logout(key, build);
      }
    }
    return true;
  }
  @Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException {
    listener.getLogger().println("[htmlpublisher] Archiving HTML reports...");

    // Grab the contents of the header and footer as arrays
    ArrayList<String> headerLines;
    ArrayList<String> footerLines;
    try {
      headerLines = this.readFile("/htmlpublisher/HtmlPublisher/header.html");
      footerLines = this.readFile("/htmlpublisher/HtmlPublisher/footer.html");
    } catch (FileNotFoundException e1) {
      e1.printStackTrace();
      return false;
    } catch (IOException e1) {
      e1.printStackTrace();
      return false;
    }

    for (int i = 0; i < this.reportTargets.size(); i++) {
      // Create an array of lines we will eventually write out, initially the header.
      ArrayList<String> reportLines = new ArrayList<String>(headerLines);
      HtmlPublisherTarget reportTarget = this.reportTargets.get(i);
      boolean keepAll = reportTarget.getKeepAll();

      FilePath archiveDir =
          build
              .getWorkspace()
              .child(resolveParametersInString(build, listener, reportTarget.getReportDir()));
      FilePath targetDir = reportTarget.getArchiveTarget(build);

      String levelString = keepAll ? "BUILD" : "PROJECT";
      listener
          .getLogger()
          .println(
              "[htmlpublisher] Archiving at "
                  + levelString
                  + " level "
                  + archiveDir
                  + " to "
                  + targetDir);

      // The index name might be a comma separated list of names, so let's figure out all the pages
      // we should index.
      String[] csvReports =
          resolveParametersInString(build, listener, reportTarget.getReportFiles()).split(",");
      ArrayList<String> reports = new ArrayList<String>();
      for (int j = 0; j < csvReports.length; j++) {
        String report = csvReports[j];
        report = report.trim();

        // Ignore blank report names caused by trailing or double commas.
        if (report.equals("")) {
          continue;
        }

        reports.add(report);
        String tabNo = "tab" + (j + 1);
        // Make the report name the filename without the extension.
        int end = report.lastIndexOf(".");
        String reportName;
        if (end > 0) {
          reportName = report.substring(0, end);
        } else {
          reportName = report;
        }
        String tabItem =
            "<li id=\""
                + tabNo
                + "\" class=\"unselected\" onclick=\"updateBody('"
                + tabNo
                + "');\" value=\""
                + report
                + "\">"
                + reportName
                + "</li>";
        reportLines.add(tabItem);
      }
      // Add the JS to change the link as appropriate.
      String hudsonUrl = Hudson.getInstance().getRootUrl();
      AbstractProject job = build.getProject();
      reportLines.add(
          "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").innerHTML=\"Back to "
              + job.getName()
              + "\";</script>");
      // If the URL isn't configured in Hudson, the best we can do is attempt to go Back.
      if (hudsonUrl == null) {
        reportLines.add(
            "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").onclick = function() { history.go(-1); return false; };</script>");
      } else {
        String jobUrl = hudsonUrl + job.getUrl();
        reportLines.add(
            "<script type=\"text/javascript\">document.getElementById(\"hudson_link\").href=\""
                + jobUrl
                + "\";</script>");
      }

      reportLines.add(
          "<script type=\"text/javascript\">document.getElementById(\"zip_link\").href=\"*zip*/"
              + reportTarget.getSanitizedName()
              + ".zip\";</script>");

      try {
        if (!archiveDir.exists()) {
          listener.error("Specified HTML directory '" + archiveDir + "' does not exist.");
          build.setResult(Result.FAILURE);
          return true;
        } else if (!keepAll) {
          // We are only keeping one copy at the project level, so remove the old one.
          targetDir.deleteRecursive();
        }

        if (archiveDir.copyRecursiveTo("**/*", targetDir) == 0) {
          listener.error(
              "Directory '" + archiveDir + "' exists but failed copying to '" + targetDir + "'.");
          if (build.getResult().isBetterOrEqualTo(Result.UNSTABLE)) {
            // If the build failed, don't complain that there was no coverage.
            // The build probably didn't even get to the point where it produces coverage.
            listener.error("This is especially strange since your build otherwise succeeded.");
          }
          build.setResult(Result.FAILURE);
          return true;
        }
      } catch (IOException e) {
        Util.displayIOException(e, listener);
        e.printStackTrace(listener.fatalError("HTML Publisher failure"));
        build.setResult(Result.FAILURE);
        return true;
      }

      reportTarget.handleAction(build);

      // Now add the footer.
      reportLines.addAll(footerLines);
      // And write this as the index
      try {
        writeFile(reportLines, new File(targetDir.getRemote(), reportTarget.getWrapperName()));
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    return true;
  }
 public void error(Throwable throwable, String message, Object... args) {
   listener.fatalError(String.format(message, args) + ": " + throwable.getCause());
 }
 public void error(String message, Object... args) {
   listener.fatalError(String.format(message, args));
 }
  /** {@inheritDoc} */
  public boolean perform(Build<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException, IOException {
    if (coverageReportPattern == null) {
      listener.getLogger().println("Skipping coverage reports as coverageReportPattern is null");
      return false;
    }
    if (!Result.SUCCESS.equals(build.getResult())) {
      listener.getLogger().println("Skipping coverage reports as the build was not successful...");
      return true;
    }

    listener.getLogger().println("Publishing PureCoverage reports...");
    FilePath buildTarget = new FilePath(build.getRootDir());

    FilePath[] reports = new FilePath[0];
    final FilePath moduleRoot = build.getParent().getWorkspace();
    try {
      reports = moduleRoot.list(coverageReportPattern);
    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("Unable to find PureCoverage results"));
      build.setResult(Result.FAILURE);
    }

    if (reports.length == 0) {
      listener
          .getLogger()
          .println(
              "No coverage results were found using the pattern '"
                  + coverageReportPattern
                  + "'.  Did you generate the report(s)?");
      build.setResult(Result.FAILURE);
      return true;
    }

    if (reports.length > 1) {
      listener
          .getLogger()
          .println(
              "PureCoverage publisher found more than one report that match the pattern. "
                  + "Currently, accumulating PureCoverage results is not implemented!");
      build.setResult(Result.FAILURE);
      return true;
    }

    FilePath singleReport = reports[0];
    final FilePath targetPath = new FilePath(buildTarget, CoverageReportsFinder.COVERAGE_PREFIX);
    try {
      singleReport.copyTo(targetPath);
    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(
          listener.fatalError(
              "Unable to copy coverage from " + singleReport + " to " + buildTarget));
      build.setResult(Result.FAILURE);
    }

    listener.getLogger().println("Parsing PureCoverage results...");
    ProjectCoverage projectCoverage = null;
    CoverageReportsFinder finder = new CoverageReportsFinder();
    for (File coverageResult : finder.findReports(build)) {
      try {
        CoverageParser coverageParser = new PureCoverageParser();
        projectCoverage = coverageParser.parse(coverageResult);
      } catch (IOException e) {
        Util.displayIOException(e, listener);
        e.printStackTrace(listener.fatalError("Unable to parse " + coverageResult));
        build.setResult(Result.FAILURE);
        return false;
      }
    }

    CoverageResult coverageResult = new CoverageResult(build, projectCoverage);
    build.getActions().add(new CoverageBuildAction(build, coverageResult));

    return true;
  }
  /** {@inheritDoc} */
  @Override
  public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
      throws InterruptedException, IOException {
    Result threshold = onlyStable ? Result.SUCCESS : Result.UNSTABLE;
    if (build.getResult().isWorseThan(threshold)) {
      listener
          .getLogger()
          .println(
              "Skipping Cobertura coverage report as build was not "
                  + threshold.toString()
                  + " or better ...");
      return true;
    }

    listener.getLogger().println("[Cobertura] Publishing Cobertura coverage report...");
    final FilePath[] moduleRoots = build.getModuleRoots();
    final boolean multipleModuleRoots = moduleRoots != null && moduleRoots.length > 1;
    final FilePath moduleRoot = multipleModuleRoots ? build.getWorkspace() : build.getModuleRoot();
    final File buildCoberturaDir = build.getRootDir();
    FilePath buildTarget = new FilePath(buildCoberturaDir);

    FilePath[] reports = new FilePath[0];
    try {
      reports = moduleRoot.act(new ParseReportCallable(coberturaReportFile));

      // if the build has failed, then there's not
      // much point in reporting an error
      if (build.getResult().isWorseOrEqualTo(Result.FAILURE) && reports.length == 0) {
        return true;
      }

    } catch (IOException e) {
      Util.displayIOException(e, listener);
      e.printStackTrace(listener.fatalError("Unable to find coverage results"));
      build.setResult(Result.FAILURE);
    }

    if (reports.length == 0) {
      String msg =
          "[Cobertura] No coverage results were found using the pattern '"
              + coberturaReportFile
              + "' relative to '"
              + moduleRoot.getRemote()
              + "'."
              + "  Did you enter a pattern relative to the correct directory?"
              + "  Did you generate the XML report(s) for Cobertura?";
      listener.getLogger().println(msg);
      if (failNoReports) {
        build.setResult(Result.FAILURE);
      } else {
        listener.getLogger().println("[Cobertura] Skipped cobertura reports.");
      }
      return true;
    }

    for (int i = 0; i < reports.length; i++) {
      final FilePath targetPath =
          new FilePath(buildTarget, "coverage" + (i == 0 ? "" : i) + ".xml");
      try {
        reports[i].copyTo(targetPath);
      } catch (IOException e) {
        Util.displayIOException(e, listener);
        e.printStackTrace(
            listener.fatalError(
                "Unable to copy coverage from " + reports[i] + " to " + buildTarget));
        build.setResult(Result.FAILURE);
      }
    }

    listener.getLogger().println("Publishing Cobertura coverage results...");
    Set<String> sourcePaths = new HashSet<String>();
    CoverageResult result = null;
    for (File coberturaXmlReport : getCoberturaReports(build)) {
      try {
        result = CoberturaCoverageParser.parse(coberturaXmlReport, result, sourcePaths);
      } catch (IOException e) {
        Util.displayIOException(e, listener);
        e.printStackTrace(listener.fatalError("Unable to parse " + coberturaXmlReport));
        build.setResult(Result.FAILURE);
      }
    }
    if (result != null) {
      listener.getLogger().println("Cobertura coverage report found.");
      result.setOwner(build);
      final FilePath paintedSourcesPath =
          new FilePath(new File(build.getProject().getRootDir(), "cobertura"));
      paintedSourcesPath.mkdirs();

      if (sourcePaths.contains(".")) {
        sourcePaths.remove(".");
        for (FilePath f : reports) {
          FilePath p = f.getParent();
          if (p != null && p.isDirectory()) {
            sourcePaths.add(p.getRemote());
          }
        }
      }

      SourceCodePainter painter =
          new SourceCodePainter(
              paintedSourcesPath,
              sourcePaths,
              result.getPaintedSources(),
              listener,
              getSourceEncoding());

      moduleRoot.act(painter);

      final CoberturaBuildAction action =
          CoberturaBuildAction.load(
              build,
              result,
              healthyTarget,
              unhealthyTarget,
              getOnlyStable(),
              getFailUnhealthy(),
              getFailUnstable(),
              getAutoUpdateHealth(),
              getAutoUpdateStability());

      build.getActions().add(action);
      Set<CoverageMetric> failingMetrics = failingTarget.getFailingMetrics(result);
      if (!failingMetrics.isEmpty()) {
        listener.getLogger().println("Code coverage enforcement failed for the following metrics:");
        float oldStabilityPercent;
        float setStabilityPercent;
        for (CoverageMetric metric : failingMetrics) {
          oldStabilityPercent = failingTarget.getObservedPercent(result, metric);
          setStabilityPercent = failingTarget.getSetPercent(result, metric);
          listener
              .getLogger()
              .println(
                  "    "
                      + metric.getName()
                      + "'s stability is "
                      + roundDecimalFloat(oldStabilityPercent * 100f)
                      + " and set mininum stability is "
                      + roundDecimalFloat(setStabilityPercent * 100f)
                      + ".");
        }
        if (!getFailUnstable()) {
          listener.getLogger().println("Setting Build to unstable.");
          build.setResult(Result.UNSTABLE);
        } else {
          listener.getLogger().println("Failing build due to unstability.");
          build.setResult(Result.FAILURE);
        }
      }
      if (getFailUnhealthy()) {
        Set<CoverageMetric> unhealthyMetrics = unhealthyTarget.getFailingMetrics(result);
        if (!unhealthyMetrics.isEmpty()) {
          listener.getLogger().println("Unhealthy for the following metrics:");
          float oldHealthyPercent;
          float setHealthyPercent;
          for (CoverageMetric metric : unhealthyMetrics) {
            oldHealthyPercent = unhealthyTarget.getObservedPercent(result, metric);
            setHealthyPercent = unhealthyTarget.getSetPercent(result, metric);
            listener
                .getLogger()
                .println(
                    "    "
                        + metric.getName()
                        + "'s health is "
                        + roundDecimalFloat(oldHealthyPercent * 100f)
                        + " and set minimum health is "
                        + roundDecimalFloat(setHealthyPercent * 100f)
                        + ".");
          }
          listener.getLogger().println("Failing build because it is unhealthy.");
          build.setResult(Result.FAILURE);
        }
      }
      if (build.getResult() == Result.SUCCESS) {
        if (getAutoUpdateHealth()) {
          setNewPercentages(result, true, listener);
        }

        if (getAutoUpdateStability()) {
          setNewPercentages(result, false, listener);
        }
      }
    } else {
      listener
          .getLogger()
          .println(
              "No coverage results were successfully parsed.  Did you generate "
                  + "the XML report(s) for Cobertura?");
      build.setResult(Result.FAILURE);
    }

    return true;
  }